创建线程,实现接口优于继承Thread
Java不支持多继承,因此继承了Thread类就无法继承其他类;
类可能只要求可执行就可,继承Thread开销过大。
基础线程机制 Executor Executor管理多个异步任务的执行,无需程序员显式地管理线程的生命周期。
目前有三种Executor:
CachedThreadPool
:一个任务创建一个线程;
FixedThreadPool
:所有任务使用固定数量的线程,多出来的排队或丢弃,取决于初始化参数;
SingleThreadExecutor
:大小为1的FixedThreadPool
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class ExecutorStudy { public static void main (String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(5 ); for (int i = 0 ; i < 30 ; i++) { executorService.execute(()->{ System.out.println(Thread.currentThread().getName()+" Execute." ); try { TimeUnit.MILLISECONDS.sleep(500 ); } catch (InterruptedException e) { e.printStackTrace(); } }); } executorService.shutdown(); } }
Daemon Daemon,即守护线程。
守护线程是程序运行时在后台提供服务的线程,不是程序中不可或缺的部分 。
当所有非守护线程结束时,程序也将终止,同时会杀死所有守护线程。
主线程不是守护线程;
使用setDaemon()
可以设置一个线程为守护线程。
1 2 3 4 Thread thread = new Thread (() -> { System.out.println("这即将是一个守护线程" ); }); thread.setDaemon(true );
sleep() 休眠当前线程为指定时间。
1 2 3 4 5 6 Thread thread = new Thread (() -> { System.out.println("这是一个线程" ); try { Thread.sleep(3000 ); }catch (Exception e){e.printStackTrace();} });
yield() Thread.yield()
表示当前线程已经完成了生命周期中最重要的部分。
这个方法只是给线程调度器一个建议,且只是建议具有相同优先级的其他线程 可以运行。
1 2 3 4 Thread thread = new Thread (() -> { System.out.println("这是一个线程" ); Thread.yield(); });
线程中断 一个线程执行完毕后会自动结束,如果在运行过程中发生异常也会提前结束.
InterruptedException 当对一个线程使用了interrupt()方法,若线程处于阻塞、限期等待或无限期等待状态,就会抛出InterruptedException异常,从而提前结束该线程。
不能终端I/O阻塞和synchronized阻塞。
示例:sleep()限期阻塞。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void main (String[] args) throws InterruptedException { Thread thread = new Thread (() -> { int cnt = 0 ; try { while (true ) { System.out.println("执行 " + cnt++); Thread.sleep(1000 ); } } catch (Exception e) { e.printStackTrace(); } }, "一个线程" ); thread.start(); Thread.sleep(3500 ); thread.interrupt(); }
1 2 3 4 5 6 7 8 9 10 执行 0 执行 1 执行 2 执行 3 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.yn.ExecutorStudy.lambda$main$0(ExecutorStudy.java:37) at java.lang.Thread.run(Thread.java:748) Process finished with exit code 0
interrupted() 如果一个线程的run()无限循环且没有sleep()方法,此时调用interrupt()方法就无法使线程提前结束。
在线程内可以用interrupted()来获取线程是否执行过interrupt,在线程内控制是否接收interrupt中断。
1 2 3 4 5 6 7 8 9 10 11 public static void main (String[] args) throws InterruptedException { Thread thread = new Thread (() -> { int cnt = 0 ; while (!Thread.interrupted()) { System.out.println("执行 " + cnt++); } System.out.println("线程结束" ); }, "一个线程" ); thread.start(); thread.interrupt(); }
Executor的中断操作 Executor可以通过shutdown()方法或shutdownNow()方法来关闭Executor服务。
shutdown()会等待线程执行完毕后在进行服务关闭;
shutdownNow()会调用每个线程的interrupt方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ExecutorStudy2 { public static void main (String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(()->{ try { while (true ){ System.out.println("线程执行" ); Thread.sleep(300 ); } }catch (Exception e){e.printStackTrace();} System.out.println("线程结束" ); }); executorService.shutdownNow(); } }
1 2 3 4 5 6 7 8 9 线程执行 线程结束 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.yn.ExecutorStudy2.lambda$main$0(ExecutorStudy2.java:13) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
通过submit()方法提交任务,可以获得一个Future对象,通过future对象可以独立控制单个线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public static void main (String[] args) throws InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Future<?> submit = executorService.submit(() -> { try { while (true ) { System.out.println("线程执行" ); Thread.sleep(300 ); } } catch (Exception e) { e.printStackTrace(); } System.out.println("线程结束" ); }); Thread.sleep(1000 ); submit.cancel(true ); executorService.shutdown(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 线程执行 线程执行 线程执行 线程执行 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.yn.FutureStudy.lambda$main$0(FutureStudy.java:14) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 线程结束 Process finished with exit code 0
线程互斥同步 Java提供了两种锁机制来控制多个线程对共享资源的互斥访问。
JVM实现的synchronized 同步
JDK实现的ReentrantLock 可重入锁
synchronized 使用synchronized使用多个方式实现同步。