• 2 Java并发原理精讲课程学习笔记


    1.1、初始线程8大核心基础

    1. 实现多线程的方法到底有1种还是2种还是4种?
    2. 怎样才是正确的线程启动方式?
    3. 如何正确停止线程?
    4. 线程的一生——6个状态(生命周期)
    5. Thread和Object类中的重要方法详解
    6. 线程的各个属性
    7. 未捕获异常如何处理?
    8. 双刃剑:多线程会导致的问题

    2.1、核心1:实现多线程的正确姿势

    2.1.1、创建新线程

    问题:实现多线程的方法是1种还是2种还是4种?

    创建线程2种方式:
    1.实现Runanble接口(推荐)->作为参数传入
    代码演示:
    
    1. /**
    2. * 描述: 用Runnable方式创建线程
    3. */
    4. public class RunnableStyle implements Runnable{
    5. public static void main(String[] args) {
    6. Thread thread = new Thread(new RunnableStyle());
    7. thread.start();
    8. }
    9. @Override
    10. public void run() {
    11. System.out.println("用Runnable方法实现线程");
    12. }
    13. }
    执行结果:
    
    用Runnable方法实现线程
    2.继承Thread类
    代码演示:
    
    1. /**
    2. * 描述: 用Thread方式实现线程
    3. */
    4. public class ThreadStyle extends Thread{
    5. @Override
    6. public void run() {
    7. System.out.println("用Thread类实现线程");
    8. }
    9. public static void main(String[] args) {
    10. new ThreadStyle().start();
    11. }
    12. }

    执行结果:

    用Thread类实现线程

    两种方法对比

    方法1(实现Runnable接口)更好

    实现Runnable接口好在哪里?

    继承Thread类是不推荐的,因为它有以下的一些缺点:

    1. 从代码架构角度:具体的任务(run方法)应该和“创建和运行线程的机制(Thread类)”解耦,用runnable对象可以实现解耦。
    2. 使用继承Thread的方式的话,那么每次想新建一个任务,只能新建一个独立的线程,而这样做的损耗会比较大(比如重头开始创建一个线程、执行完毕以后再销毁等。如果线程的实际工作内容,也就是run()函数里只是简单的打印一行文字的话,那么可能线程的实际工作内容还不如损耗来的大)。如果使用Runnable和线程池,就可以大大减小这样的损耗。
    3. 继承Thread类以后,由于Java语言不支持双继承,这样就无法再继承其他的类,限制了可扩展性。
      通常我们优先选择方法1。

    两种方法的本质对比

    方法一和方法二,也就是“实现Runnable接口并传入Thread类”和“继承Thread类然后重写run()”在实现多线程的本质上,并没有区别,都是最终调用了start()方法来新建线程。这两个方法的最主要区别在于run()方法的内容来源:

    1. @Override
    2. public void run() {
    3. if (target != null) {
    4. target.run();
    5. }
    6. }

    方法一:最终调用target.run();
    方法二:run()整个都被重写

    面试问题:有多少种实现线程的方法

    题目描述:有多少种实现线程的方法?典型错误答案和正确答案。(问题选自《常见面试题汇总》)
    提示:答题思路,以下5点:
    1. 从不同的角度看,会有不同的答案。
    2. 典型答案是两种,分别是实现Runnable接口和继承Thread类,然后具体展开说;
    3. 但是,我们看原理,其实Thread类实现了Runnable接口,并且看Thread类的run方法,会发现其实那两种本质都是一样的,run方法的代码如下:

    @Override
    public void run() {
    if (target != null) {
    target.run();
    }
    }

    方法一和方法二,也就是“继承Thread类然后重写run()”和“实现Runnable接口并传入Thread类”在实现多线程的本质上,并没有区别,都是最终调用了start()方法来新建线程。这两个方法的最主要区别在于run()方法的内容来源:
    方法一:最终调用target.run();
    方法二:run()整个都被重写

    4. 然后具体展开说其他方式:还有其他的实现线程的方法,例如线程池、定时器,它们也能新建线程,但是细看源码,从没有逃出过本质,也就是实现Runnable接口和继承Thread类。
    5. 结论:我们只能通过新建Thread类这一种方式来创建线程,但是类里面的run方法有两种方式来实现,第一种是重写run方法,第二种实现Runnable接口的run方法,然后再把该runnable实例传给Thread类。除此之外,从表面上看线程池、定时器等工具类也可以创建线程,但是它们的本质都逃不出刚才所说的范围。

    以上这种描述比直接回答一种、两种、多种都更准确。

    2.1.2、同时使用两种方法创建线程会怎样?

    代码演示:

    1. /**
    2. * 描述: 同时使用Runnable和Thread两种实现线程的方式。思路来自于网上的相同思路的面试题。
    3. */
    4. public class BothRunnableThread {
    5. public static void main(String[] args) {
    6. new Thread(new Runnable() {
    7. @Override
    8. public void run() {
    9. System.out.println("我来自Runnable");
    10. }
    11. }) {
    12. @Override
    13. public void run() {
    14. System.out.println("我来自Thread");
    15. }
    16. }.start();
    17. }
    18. }

    运行结果:

    我来自Thread

    2.2、核心2:怎样才是正确的线程启动方式?

    2.2.1、启动线程的正确和错误方式

    1. start()和run()的比较
    2. start()方法原理解读
    3. run()方法原理解读

    start()和run()的比较

    代码演示:

    1. /**
    2. * 描述: 对比start和run两种启动线程的方式
    3. */
    4. public class StartAndRunMethod {
    5. public static void main(String[] args) {
    6. Runnable runnable = () -> {
    7. System.out.println(Thread.currentThread().getName());
    8. };
    9. runnable.run();// main
    10. new Thread(runnable).start(); // Thread-0
    11. }
    12. }

    运行结果:

    1. main
    2. Thread-0
    主线程调用子线程start()方法:
    主线程会通知JVM在空闲的时间启动子线程,但启动子线程的时机是由JVM线程调度器来决定的,所以说即使调用了start()方法,也不一定会立即启动子线程,所以调用start线程的顺序,并不能决定线程执行的顺序
    子线程的创建准备工作:
    1、处于就绪状态(获取到了除了CPU以外的所有资源,如:上下文、栈、线程状态)
    做完准备工作,线程才能够被JVM调度到执行状态,等待获取CPU资源,然后才能够真正到运行状态
    不能两次调用start方法,否则会报错。
    

    演示:

    1. /**
    2. * 描述: 演示不能两次调用start方法,否则会报错
    3. */
    4. public class CantStartTwice {
    5. public static void main(String[] args) {
    6. Thread thread = new Thread();
    7. thread.start();
    8. thread.start();
    9. }

    报错信息:

    1. Exception in thread "main" java.lang.IllegalThreadStateException
    2. at java.base/java.lang.Thread.start(Thread.java:793)
    3. at com.lvxiaosha.threadcoreknowledge.startthread.CantStartTwice.main(CantStartTwice.java:10)

    报错原因:线程开始执行,从new状态到后续的状态,线程执行完毕,就会变为终止状态,而终止状态永远不可能会返回回去,所以才会抛出异常。

    start方法的执行流程是什么?

    1. 检查线程状态,只有NEW状态下的线程才能继续,否则会抛出IllegalThreadStateException(在运行中或者已结束的线程,都不能再次启动,详见CantStartTwice10类)
    2. 被加入线程组
    3. 调用start0()方法启动线程

    注意点:
    start方法是被synchronized修饰的方法,可以保证线程安全;
    由JVM创建的main方法线程和system组线程,并不会通过start来启动。

    run方法经典的3行代码
    源码分析
    public void run() {
    if (target != null) {
    target.run();
    }
    }
    两种情况 :
    target = null 时候;
    直接跳过不执行任何操作;
    !null 时候
    执行重写run方法(看第二章巩固下)

    如果要启动一个线程必须要调用thread的run方法去启动。

    面试问题:

    启动线程常见面试问题
    1、一个线程两次调用start()方法会出现什么情况?为什么?
    Java的线程是不允许启动两次的,启动第二次会出现IllegalThreadStateException异常,这是一种运行时异常,多次调用start被认为是编程错误。因为在Java5以后,线程的状态会被明确的写入其公共内部枚举类型Java.lang.Thread.State中,分别是:新建,就绪,阻塞,等待、计时等待,终止。在第二次调用start() 方法的时候,已经被start的线程已经不再是(NEW)状态了,所以无论如何是不能再次启动的。
    2、既然start()方法会调用run()方法,为什么我们选择调用start()方法,而不是直接掉用run()方法?
    调用start方法是真正意义上启动了一个线程,会经历线程的各个生命周期。如果直接调用run()方法,就是一个普通的方法而已,不是使用子线程去调用。

    2.3、核心3:如何正确停止线程?

    2.3.1、停止线程

    原理介绍:使用interrupt来通知,而不是强制停止线程。

    Java中停止线程的原则是什么?

            在Java中,最好的停止线程的方式是使用中断interrupt,但是这仅仅是会通知到被终止的线程“你该停止运行了”,被终止的线程自身拥有决定权(决定是否、以及何时停止),这依赖于请求停止方和被停止方都遵守一种约定好的编码规范。

            任务和线程的启动很容易。在大多数时候,我们都会让它们运行直到结束,或者让它们自行停止。然而,有时候我们希望提前结束任务或线程,或许是因为用户取消了操作,或者服务需要被快速关闭,或者是运行超时或出错了。
            要使任务和线程能安全、快速、可靠地停止下来,并不是一件容易的事。Java没有提供任何机制来安全地终止线程。但它提供了中断( Interruption),这是一种协作机制,能够使一个线程终止另一个线程的当前工作。
            这种协作式的方法是必要的,我们很少希望某个任务、线程或服务立即停止,因为这种立即停止会使共享的数据结构处于不一致的状态。相反,在编写任务和服务时可以使用一种协作的方式:当需要停止时,它们首先会清除当前正在执行的工作,然后再结束。这提供了更好的灵活性,因为任务本身的代码比发出取消请求的代码更清楚如何执行清除工作。
            生命周期结束(End-of-Lifecycle)的问题会使任务、服务以及程序的设计和实现等过程变得复杂,而这个在程序设计中非常重要的要素却经常被忽略。一个在行为良好的软件与勉强运的软件之间的最主要区别就是,行为良好的软件能很完善地处理失败、关闭和取消等过程。

    线程停止的情况
    1、run方法的代码执行完毕
    2、出现异常,并且方法中没有捕获

    普通情况下停止线程的代码演示:

    1. /**
    2. * 描述: run方法内没有sleep或wait方法时,停止线程
    3. */
    4. public class RightWayStopThreadWithoutSleep implements Runnable {
    5. @Override
    6. public void run() {
    7. int num = 0;
    8. while (!Thread.currentThread().isInterrupted() && num <= Integer.MAX_VALUE / 2) {
    9. if (num % 10000 == 0) {
    10. System.out.println(num + "是10000的倍数");
    11. }
    12. num++;
    13. }
    14. System.out.println("任务运行结束了");
    15. }
    16. public static void main(String[] args) throws InterruptedException {
    17. Thread thread = new Thread(new RightWayStopThreadWithoutSleep());
    18. thread.start();
    19. Thread.sleep(2000);
    20. thread.interrupt();
    21. }
    22. }

    阻塞情况下停止线程代码演示:

    1. /**
    2. * 描述: 带有sleep的中断线程的写法
    3. */
    4. public class RightWayStopThreadWithSleep {
    5. public static void main(String[] args) throws InterruptedException {
    6. Runnable runnable = () -> {
    7. int num = 0;
    8. try {
    9. while (num <= 300 && !Thread.currentThread().isInterrupted()) {
    10. if (num % 100 == 0) {
    11. System.out.println(num + "是100的倍数");
    12. }
    13. num++;
    14. }
    15. Thread.sleep(1000);
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. };
    20. Thread thread = new Thread(runnable);
    21. thread.start();
    22. Thread.sleep(500);
    23. thread.interrupt();
    24. }
    25. }

    运行结果:

    1. 0100的倍数
    2. 100100的倍数
    3. 200100的倍数
    4. 300100的倍数
    5. java.lang.InterruptedException: sleep interrupted
    6. at java.base/java.lang.Thread.sleep(Native Method)
    7. at com.lvxiaosha.threadcoreknowledge.stopthreads.RightWayStopThreadWithSleep.lambda$main$0(RightWayStopThreadWithSleep.java:18)
    8. at java.base/java.lang.Thread.run(Thread.java:833)
    Thread.sleep时可以感应到别的线程提出的interrupt请求,抛出InterruptedException。

    线程在每次迭代后都阻塞的情况停止线程代码演示:

    1. /**
    2. * 描述: 如果在执行过程中,每次循环都会调用sleep或wait等方法,那么不需要每次迭代都检查是否已中断
    3. */
    4. public class RightWayStopThreadWithSleepEveryLoop {
    5. public static void main(String[] args) throws InterruptedException {
    6. Runnable runnable = () -> {
    7. int num = 0;
    8. try {
    9. while (num <= 10000) {
    10. if (num % 100 == 0) {
    11. System.out.println(num + "是100的倍数");
    12. }
    13. num++;
    14. Thread.sleep(10);
    15. }
    16. } catch (InterruptedException e) {
    17. e.printStackTrace();
    18. }
    19. };
    20. Thread thread = new Thread(runnable);
    21. thread.start();
    22. Thread.sleep(5000);
    23. thread.interrupt();
    24. }
    25. }

    运行结果:

    1. 0100的倍数
    2. 100100的倍数
    3. 200100的倍数
    4. 300100的倍数
    5. 400100的倍数
    6. java.lang.InterruptedException: sleep interrupted
    7. at java.base/java.lang.Thread.sleep(Native Method)
    8. at com.lvxiaosha.threadcoreknowledge.stopthreads.RightWayStopThreadWithSleepEveryLoop.lambda$main$0(RightWayStopThreadWithSleepEveryLoop.java:16)
    9. at java.base/java.lang.Thread.run(Thread.java:833)
    每次迭代都会阻塞:
        这种情况,线程耗时主要集中在sleep或其他阻塞方法上,其他的操作执行的是很快的。当我们发出一个中断信号后,能够响应这个信号的代码应该就是这个sleep方法,又因为sleep方法可以正确的响应中断,所以在每次循环时就没有必要再检查当前线程是否已经被中断(Thread.currentThreah.isInterrupted())。

            在实际业务中,为了保险起见,最好还是while多判断一次。

    如果while里面放try/catch,会导致中断失效。

    代码演示:

    1. /**
    2. * 描述: 如果while里面放try/catch,会导致中断失效
    3. */
    4. public class CantInterrupt {
    5. public static void main(String[] args) throws InterruptedException {
    6. Runnable runnable = () -> {
    7. int num = 0;
    8. while (num <= 10000 && !Thread.currentThread().isInterrupted()) {
    9. if (num % 100 == 0) {
    10. System.out.println(num + "是100的倍数");
    11. }
    12. num++;
    13. try {
    14. Thread.sleep(10);
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. };
    20. Thread thread = new Thread(runnable);
    21. thread.start();
    22. Thread.sleep(5000);
    23. thread.interrupt();
    24. }
    25. }

    运行结果:

    1. 0100的倍数
    2. 100100的倍数
    3. 200100的倍数
    4. 300100的倍数
    5. 400100的倍数
    6. java.lang.InterruptedException: sleep interrupted
    7. at java.base/java.lang.Thread.sleep(Native Method)
    8. at com.lvxiaosha.threadcoreknowledge.stopthreads.CantInterrupt.lambda$main$0(CantInterrupt.java:17)
    9. at java.base/java.lang.Thread.run(Thread.java:833)
    10. 500100的倍数
    11. 600100的倍数
    12. 700100的倍数
    13. 800100的倍数

            可以看到程序没有终止。Java语言在设计sleep方法时,有这样的理念:一旦响应中断,会将线程的interrupt标记位清除。

    中断线程的两种最佳实践:
    1.传递中断(被线程调用的方法上抛出异常)
    2.恢复中断(在被线程调用的方法中可以try/catch异常,但是一定要继续发出相应线程的中断信号,也就是thread.interrupt)

    传递中断代码演示:

    1. /**
    2. * 描述: 最佳实践:catch了InterruptedExcetion之后的优先选择:在方法签名中抛出异常 那么在run()就会强制try/catch
    3. * RightWayStopThread相关的类思路代码参考自Java Concurrency In Practice的线程停止相关小节
    4. */
    5. public class RightWayStopThreadInProd implements Runnable {
    6. @Override
    7. public void run() {
    8. while (true && !Thread.currentThread().isInterrupted()) {
    9. System.out.println("go");
    10. try {
    11. throwInMethod();
    12. } catch (InterruptedException e) {
    13. Thread.currentThread().interrupt();
    14. //保存日志、停止程序
    15. System.out.println("保存日志");
    16. e.printStackTrace();
    17. }
    18. }
    19. }
    20. private void throwInMethod() throws InterruptedException {
    21. Thread.sleep(2000);
    22. }
    23. public static void main(String[] args) throws InterruptedException {
    24. Thread thread = new Thread(new RightWayStopThreadInProd());
    25. thread.start();
    26. Thread.sleep(1000);
    27. thread.interrupt();
    28. }
    29. }

    运行结果:

    1. go
    2. 保存日志
    3. java.lang.InterruptedException: sleep interrupted
    4. at java.base/java.lang.Thread.sleep(Native Method)
    5. at com.lvxiaosha.threadcoreknowledge.stopthreads.RightWayStopThreadInProd.throwInMethod(RightWayStopThreadInProd.java:25)
    6. at com.lvxiaosha.threadcoreknowledge.stopthreads.RightWayStopThreadInProd.run(RightWayStopThreadInProd.java:14)
    7. at java.base/java.lang.Thread.run(Thread.java:833)

    处理中断的最好方法是什么?

            优先选择在方法上抛出异常。
            用throws InterruptedException 标记你的方法,不采用try 语句块捕获异常,以便于该异常可以传递到顶层,让run方法可以捕获这一异常,例如:

    1. void subTask() throws InterruptedException
    2. sleep(delay);
    3. }

            由于run方法内无法抛出checked Exception(只能用try catch),顶层方法必须处理该异常,避免了漏掉或者被吞掉的情况,增强了代码的健壮性。

    恢复中断代码演示:

    1. /**
    2. * 描述:最佳实践2:在catch子语句中调用Thread.currentThread().interrupt()
    3. 来恢复设置中断状态,以便于在后续的执行中,依然能够检查到刚才发生了中断
    4. * 回到刚才RightWayStopThreadInProd补上中断,让它跳出
    5. */
    6. public class RightWayStopThreadInProd2 implements Runnable {
    7. @Override
    8. public void run() {
    9. while (true) {
    10. if (Thread.currentThread().isInterrupted()) {
    11. System.out.println("Interrupted,程序运行结束");
    12. break;
    13. }
    14. reInterrupt();
    15. }
    16. }
    17. private void reInterrupt() {
    18. try {
    19. Thread.sleep(2000);
    20. } catch (InterruptedException e) {
    21. Thread.currentThread().interrupt();
    22. e.printStackTrace();
    23. }
    24. }
    25. public static void main(String[] args) throws InterruptedException {
    26. Thread thread = new Thread(new RightWayStopThreadInProd2());
    27. thread.start();
    28. Thread.sleep(1000);
    29. thread.interrupt();
    30. }
    31. }

     

    Java异常体系

    error:程序没有办法处理
    Exception:运行时异常(非受检异常)和非运行时异常(受检异常)
    受检异常:需要处理,来提高程序的健壮性

    错误的线程停止方法

    1.stop()强制停止,停止线程会释放当前所拥有的锁,无法保证操作的原子性,可能造成脏数据
    2.suspen,resume方法不会放弃当前拥有的锁,线程挂起,可能会一直无法被唤醒或者导致死锁

    interrupt状态

    static boolean interrupted() ----针对当前运行线程,会清除状态
    public boolean isInterrupted()---针对调用线程,不会清除状态
    Thread.interrupted() 目标对象是当前执行它的线程,而不是调用它的线程
    

    练习:

    1. /**
    2. * 描述: 注意Thread.interrupted()方法的目标对象是“当前线程”,而不管本方法来自于哪个对象。
    3. * 代码出自Java并发编程之美1.7线程中断,感谢作者翟陆续
    4. */
    5. public class RightWayInterrupted {
    6. public static void main(String[] args) throws InterruptedException {
    7. Thread threadOne = new Thread(new Runnable() {
    8. @Override
    9. public void run() {
    10. for (; ; ) {
    11. }
    12. }
    13. });
    14. // 启动线程
    15. threadOne.start();
    16. //设置中断标志
    17. threadOne.interrupt();
    18. //获取中断标志
    19. System.out.println("isInterrupted: " + threadOne.isInterrupted());
    20. //获取中断标志并重置
    21. System.out.println("isInterrupted: " + threadOne.interrupted());
    22. //获取中断标志并重直
    23. System.out.println("isInterrupted: " + Thread.interrupted());
    24. //获取中断标志
    25. System.out.println("isInterrupted: " + threadOne.isInterrupted());
    26. threadOne.join();
    27. System.out.println("Main thread is over.");
    28. }
    29. }

    输出结果如下:

    1. isInterrupted: true
    2. isInterrupted: false
    3. isInterrupted: false
    4. isInterrupted: true
    isInterrupted: true --->上一行调用了interrupt,所以这里为true,不会清除这个线程的状态
    isInterrupted: false ---> interrupted是静态方法,这里不管看起来是threadOne 这个对象,或者是Thread类来进行调用,其实都是返回主线程的中断标志
    isInterrupted: false --->同上第二点
    isInterrupted: true 后面没有对threadOne线程的状态进行改变,所以依然会true

    常见面试题:

    1、如何停止线程?

    A. 用volatile的boolean作为标记来停止
    B. 用stop()方法让线程停止
    C. 用interrupt来请求线程停止

    解答:
    应该选C。

    1. 原理:用interrupt来请求线程停止而不是强制,好处是安全。
    2. 想停止线程,要请求方、被停止方、子方法被调用方相互配合才行:
      a) 作为被停止方:每次循环中或者适时检查中断信号,并且在可能抛出InterrupedException的地方处理该中断信号;
      b) 请求方:发出中断信号;
      c) 子方法调用方(被线程调用的方法的作者)要注意:优先在方法层面抛出InterrupedException,或者检查到中断信号时,再次设置中断状态;
    3. 最后再说错误的方法:stop/suspend已废弃,volatile的boolean无法处理长时间阻塞的情况

    2、无法响应中断时如何停止线程?

    A. 用interrupt方法来请求停止线程
    B. 不可中断的阻塞无法处理
    C. 根据不同的类调用不同的方法

    解答:
    应该选C。
    如果线程阻塞是由于调用了 wait(),sleep() 或 join() 方法,你可以中断线程,通过抛出 InterruptedException 异常来唤醒该线程。
    但是对于不能响应InterruptedException的阻塞,很遗憾,并没有一个通用的解决方案。
    但是我们可以利用特定的其它的可以响应中断的方法,比如ReentrantLock.lockInterruptibly(),比如关闭套接字使线程立即返回等方法来达到目的。
    答案有很多种,因为有很多原因会造成线程阻塞,所以针对不同情况,唤起的方法也不同。

    总结就是说如果不支持响应中断,就要用特定方法来唤起,没有万能药。

     2.4、核心4:线程的一生——6个状态(生命周期)

    2.4.1、线程状态

    线程的6种状态
    1、New:已经创建,但还没有启动的新线程(没有执行start方法)。
    2、Runnable:一旦调用start方法之后,处于runnable状态。
    1)调用start方法之后,线程并不会启动,可能系统没有资源分配,还处于等待状态,那这种情况下时runnable还是waiting呢,其实还是runnbale状态 ,不会从new到waiting状态。
    2)线程没有启动,为什么叫runnbale状态呢,runnbale是可运行的,而不是运行中。
    3)Java中的runnable对应os中的ready和running。
    4)runnbale既可以是可运行的,又可以是正在运行中的。
    3、Blocked
    1)线程进入被synchronize修饰的代码块之后,并且该锁被其他线程拿走,线程就是blocked状态
    2)blocked仅仅是针对synchronized这个关键字
    3)和synchronized关键字起到相似效果的还有其他锁,可重入锁、读写锁等都可以让线程进入等待的情况,但是那些情况下不是blocked的线程状态
    4、Waiting:等待唤醒
    5、Timed Waiting:计时等待(等待超时自动唤醒或者主动唤醒)
    6、Terminated:终止状态
    1)run方法执行完毕
    2)出现异常
    线程的NEW、RUNNABLE、Terminated状态代码演示:
    1. /**
    2. * 描述: 展示线程的NEW、RUNNABLE、Terminated状态。即使是正在运行,也是Runnable状态,而不是Running。
    3. */
    4. public class NewRunnableTerminated implements Runnable {
    5. public static void main(String[] args) {
    6. Thread thread = new Thread(new NewRunnableTerminated());
    7. //打印出NEW的状态
    8. System.out.println(thread.getState());
    9. thread.start();
    10. System.out.println(thread.getState());
    11. try {
    12. Thread.sleep(10);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. //打印出RUNNABLE的状态,即使是正在运行,也是RUNNABLE,而不是RUNNING
    17. System.out.println(thread.getState());
    18. try {
    19. Thread.sleep(100);
    20. } catch (InterruptedException e) {
    21. e.printStackTrace();
    22. }
    23. //打印出TERMINATED状态
    24. System.out.println(thread.getState());
    25. }
    26. @Override
    27. public void run() {
    28. for (int i = 0; i < 1000; i++) {
    29. System.out.println(i);
    30. }
    31. }
    32. }

    执行结果:

    1. NEW
    2. RUNNABLE
    3. 0
    4. 1
    5. 2
    6. 3
    7. 4
    8. 5
    9. 6
    10. 7
    11. 8
    12. 9
    13. 10
    14. 11
    15. 12
    16. 13
    17. 14
    18. 15
    19. 16
    20. 17
    21. 18
    22. 19
    23. 20
    24. 21
    25. 22
    26. 23
    27. 24
    28. 25
    29. 26
    30. 27
    31. 28
    32. 29
    33. 30
    34. 31
    35. 32
    36. 33
    37. 34
    38. 35
    39. 36
    40. 37
    41. 38
    42. 39
    43. 40
    44. 41
    45. 42
    46. 43
    47. 44
    48. 45
    49. 46
    50. 47
    51. 48
    52. 49
    53. 50
    54. 51
    55. 52
    56. 53
    57. 54
    58. 55
    59. 56
    60. 57
    61. 58
    62. 59
    63. 60
    64. 61
    65. 62
    66. 63
    67. 64
    68. 65
    69. 66
    70. 67
    71. 68
    72. 69
    73. 70
    74. 71
    75. 72
    76. 73
    77. 74
    78. 75
    79. 76
    80. 77
    81. 78
    82. 79
    83. 80
    84. 81
    85. 82
    86. 83
    87. 84
    88. 85
    89. 86
    90. 87
    91. 88
    92. 89
    93. 90
    94. 91
    95. 92
    96. 93
    97. 94
    98. 95
    99. 96
    100. 97
    101. 98
    102. 99
    103. 100
    104. 101
    105. 102
    106. 103
    107. 104
    108. 105
    109. 106
    110. 107
    111. 108
    112. 109
    113. 110
    114. 111
    115. 112
    116. 113
    117. 114
    118. 115
    119. 116
    120. 117
    121. 118
    122. 119
    123. 120
    124. 121
    125. 122
    126. 123
    127. 124
    128. 125
    129. 126
    130. 127
    131. 128
    132. 129
    133. 130
    134. 131
    135. 132
    136. 133
    137. 134
    138. 135
    139. 136
    140. 137
    141. 138
    142. 139
    143. 140
    144. 141
    145. 142
    146. 143
    147. 144
    148. 145
    149. 146
    150. 147
    151. 148
    152. 149
    153. 150
    154. 151
    155. 152
    156. 153
    157. 154
    158. 155
    159. 156
    160. 157
    161. 158
    162. 159
    163. 160
    164. 161
    165. 162
    166. 163
    167. 164
    168. 165
    169. 166
    170. 167
    171. 168
    172. 169
    173. 170
    174. 171
    175. 172
    176. 173
    177. 174
    178. 175
    179. 176
    180. 177
    181. 178
    182. 179
    183. 180
    184. 181
    185. 182
    186. 183
    187. 184
    188. 185
    189. 186
    190. 187
    191. 188
    192. 189
    193. 190
    194. 191
    195. 192
    196. 193
    197. 194
    198. 195
    199. 196
    200. 197
    201. 198
    202. 199
    203. 200
    204. 201
    205. 202
    206. 203
    207. 204
    208. 205
    209. 206
    210. 207
    211. 208
    212. 209
    213. 210
    214. 211
    215. 212
    216. 213
    217. 214
    218. 215
    219. 216
    220. 217
    221. 218
    222. 219
    223. 220
    224. 221
    225. 222
    226. 223
    227. 224
    228. 225
    229. 226
    230. 227
    231. 228
    232. 229
    233. 230
    234. 231
    235. 232
    236. 233
    237. 234
    238. 235
    239. 236
    240. 237
    241. 238
    242. 239
    243. 240
    244. 241
    245. 242
    246. 243
    247. 244
    248. 245
    249. 246
    250. 247
    251. 248
    252. 249
    253. 250
    254. 251
    255. 252
    256. 253
    257. 254
    258. 255
    259. 256
    260. 257
    261. 258
    262. 259
    263. 260
    264. 261
    265. 262
    266. 263
    267. 264
    268. 265
    269. 266
    270. 267
    271. 268
    272. 269
    273. 270
    274. 271
    275. 272
    276. 273
    277. 274
    278. 275
    279. 276
    280. 277
    281. 278
    282. 279
    283. 280
    284. 281
    285. 282
    286. 283
    287. 284
    288. 285
    289. 286
    290. 287
    291. 288
    292. 289
    293. 290
    294. 291
    295. 292
    296. 293
    297. 294
    298. 295
    299. 296
    300. 297
    301. 298
    302. 299
    303. 300
    304. 301
    305. 302
    306. 303
    307. 304
    308. 305
    309. 306
    310. 307
    311. 308
    312. 309
    313. 310
    314. 311
    315. 312
    316. 313
    317. 314
    318. 315
    319. 316
    320. 317
    321. 318
    322. 319
    323. 320
    324. 321
    325. 322
    326. 323
    327. 324
    328. 325
    329. 326
    330. 327
    331. 328
    332. 329
    333. 330
    334. 331
    335. 332
    336. 333
    337. 334
    338. 335
    339. 336
    340. 337
    341. 338
    342. 339
    343. 340
    344. 341
    345. 342
    346. 343
    347. 344
    348. 345
    349. 346
    350. 347
    351. 348
    352. 349
    353. 350
    354. 351
    355. 352
    356. 353
    357. 354
    358. 355
    359. 356
    360. 357
    361. 358
    362. 359
    363. 360
    364. 361
    365. 362
    366. 363
    367. 364
    368. 365
    369. 366
    370. 367
    371. 368
    372. 369
    373. 370
    374. 371
    375. 372
    376. 373
    377. 374
    378. 375
    379. 376
    380. 377
    381. 378
    382. 379
    383. 380
    384. 381
    385. 382
    386. 383
    387. 384
    388. 385
    389. 386
    390. 387
    391. 388
    392. 389
    393. 390
    394. 391
    395. 392
    396. 393
    397. 394
    398. 395
    399. 396
    400. 397
    401. 398
    402. 399
    403. 400
    404. 401
    405. 402
    406. 403
    407. 404
    408. 405
    409. 406
    410. 407
    411. 408
    412. 409
    413. 410
    414. 411
    415. 412
    416. 413
    417. 414
    418. 415
    419. 416
    420. 417
    421. 418
    422. 419
    423. 420
    424. 421
    425. 422
    426. 423
    427. 424
    428. 425
    429. 426
    430. 427
    431. 428
    432. 429
    433. 430
    434. 431
    435. 432
    436. 433
    437. 434
    438. 435
    439. 436
    440. 437
    441. 438
    442. 439
    443. 440
    444. 441
    445. 442
    446. 443
    447. 444
    448. 445
    449. 446
    450. 447
    451. 448
    452. 449
    453. 450
    454. 451
    455. 452
    456. 453
    457. 454
    458. 455
    459. 456
    460. 457
    461. 458
    462. 459
    463. 460
    464. 461
    465. 462
    466. 463
    467. 464
    468. 465
    469. 466
    470. 467
    471. 468
    472. 469
    473. 470
    474. 471
    475. 472
    476. 473
    477. 474
    478. 475
    479. 476
    480. 477
    481. 478
    482. 479
    483. 480
    484. 481
    485. 482
    486. 483
    487. 484
    488. 485
    489. 486
    490. 487
    491. 488
    492. 489
    493. 490
    494. 491
    495. 492
    496. 493
    497. 494
    498. 495
    499. 496
    500. 497
    501. 498
    502. 499
    503. 500
    504. 501
    505. 502
    506. 503
    507. 504
    508. 505
    509. 506
    510. 507
    511. 508
    512. 509
    513. 510
    514. 511
    515. 512
    516. 513
    517. 514
    518. 515
    519. 516
    520. 517
    521. 518
    522. 519
    523. 520
    524. 521
    525. 522
    526. 523
    527. 524
    528. 525
    529. 526
    530. 527
    531. 528
    532. 529
    533. 530
    534. 531
    535. 532
    536. 533
    537. 534
    538. 535
    539. 536
    540. 537
    541. 538
    542. 539
    543. 540
    544. 541
    545. 542
    546. 543
    547. 544
    548. 545
    549. 546
    550. 547
    551. 548
    552. 549
    553. 550
    554. 551
    555. 552
    556. 553
    557. 554
    558. 555
    559. 556
    560. 557
    561. 558
    562. 559
    563. 560
    564. 561
    565. 562
    566. 563
    567. 564
    568. 565
    569. 566
    570. 567
    571. 568
    572. 569
    573. 570
    574. 571
    575. 572
    576. 573
    577. 574
    578. 575
    579. 576
    580. 577
    581. 578
    582. 579
    583. 580
    584. 581
    585. 582
    586. 583
    587. 584
    588. 585
    589. 586
    590. 587
    591. 588
    592. 589
    593. 590
    594. 591
    595. 592
    596. 593
    597. 594
    598. 595
    599. 596
    600. 597
    601. 598
    602. 599
    603. 600
    604. 601
    605. 602
    606. 603
    607. 604
    608. 605
    609. 606
    610. 607
    611. 608
    612. 609
    613. 610
    614. 611
    615. 612
    616. 613
    617. 614
    618. 615
    619. 616
    620. 617
    621. 618
    622. 619
    623. 620
    624. 621
    625. 622
    626. 623
    627. 624
    628. 625
    629. 626
    630. 627
    631. 628
    632. 629
    633. 630
    634. 631
    635. 632
    636. 633
    637. 634
    638. 635
    639. 636
    640. 637
    641. 638
    642. 639
    643. 640
    644. 641
    645. 642
    646. 643
    647. 644
    648. 645
    649. 646
    650. 647
    651. 648
    652. 649
    653. 650
    654. 651
    655. 652
    656. 653
    657. 654
    658. 655
    659. 656
    660. 657
    661. 658
    662. 659
    663. 660
    664. 661
    665. 662
    666. 663
    667. 664
    668. 665
    669. 666
    670. RUNNABLE
    671. 667
    672. 668
    673. 669
    674. 670
    675. 671
    676. 672
    677. 673
    678. 674
    679. 675
    680. 676
    681. 677
    682. 678
    683. 679
    684. 680
    685. 681
    686. 682
    687. 683
    688. 684
    689. 685
    690. 686
    691. 687
    692. 688
    693. 689
    694. 690
    695. 691
    696. 692
    697. 693
    698. 694
    699. 695
    700. 696
    701. 697
    702. 698
    703. 699
    704. 700
    705. 701
    706. 702
    707. 703
    708. 704
    709. 705
    710. 706
    711. 707
    712. 708
    713. 709
    714. 710
    715. 711
    716. 712
    717. 713
    718. 714
    719. 715
    720. 716
    721. 717
    722. 718
    723. 719
    724. 720
    725. 721
    726. 722
    727. 723
    728. 724
    729. 725
    730. 726
    731. 727
    732. 728
    733. 729
    734. 730
    735. 731
    736. 732
    737. 733
    738. 734
    739. 735
    740. 736
    741. 737
    742. 738
    743. 739
    744. 740
    745. 741
    746. 742
    747. 743
    748. 744
    749. 745
    750. 746
    751. 747
    752. 748
    753. 749
    754. 750
    755. 751
    756. 752
    757. 753
    758. 754
    759. 755
    760. 756
    761. 757
    762. 758
    763. 759
    764. 760
    765. 761
    766. 762
    767. 763
    768. 764
    769. 765
    770. 766
    771. 767
    772. 768
    773. 769
    774. 770
    775. 771
    776. 772
    777. 773
    778. 774
    779. 775
    780. 776
    781. 777
    782. 778
    783. 779
    784. 780
    785. 781
    786. 782
    787. 783
    788. 784
    789. 785
    790. 786
    791. 787
    792. 788
    793. 789
    794. 790
    795. 791
    796. 792
    797. 793
    798. 794
    799. 795
    800. 796
    801. 797
    802. 798
    803. 799
    804. 800
    805. 801
    806. 802
    807. 803
    808. 804
    809. 805
    810. 806
    811. 807
    812. 808
    813. 809
    814. 810
    815. 811
    816. 812
    817. 813
    818. 814
    819. 815
    820. 816
    821. 817
    822. 818
    823. 819
    824. 820
    825. 821
    826. 822
    827. 823
    828. 824
    829. 825
    830. 826
    831. 827
    832. 828
    833. 829
    834. 830
    835. 831
    836. 832
    837. 833
    838. 834
    839. 835
    840. 836
    841. 837
    842. 838
    843. 839
    844. 840
    845. 841
    846. 842
    847. 843
    848. 844
    849. 845
    850. 846
    851. 847
    852. 848
    853. 849
    854. 850
    855. 851
    856. 852
    857. 853
    858. 854
    859. 855
    860. 856
    861. 857
    862. 858
    863. 859
    864. 860
    865. 861
    866. 862
    867. 863
    868. 864
    869. 865
    870. 866
    871. 867
    872. 868
    873. 869
    874. 870
    875. 871
    876. 872
    877. 873
    878. 874
    879. 875
    880. 876
    881. 877
    882. 878
    883. 879
    884. 880
    885. 881
    886. 882
    887. 883
    888. 884
    889. 885
    890. 886
    891. 887
    892. 888
    893. 889
    894. 890
    895. 891
    896. 892
    897. 893
    898. 894
    899. 895
    900. 896
    901. 897
    902. 898
    903. 899
    904. 900
    905. 901
    906. 902
    907. 903
    908. 904
    909. 905
    910. 906
    911. 907
    912. 908
    913. 909
    914. 910
    915. 911
    916. 912
    917. 913
    918. 914
    919. 915
    920. 916
    921. 917
    922. 918
    923. 919
    924. 920
    925. 921
    926. 922
    927. 923
    928. 924
    929. 925
    930. 926
    931. 927
    932. 928
    933. 929
    934. 930
    935. 931
    936. 932
    937. 933
    938. 934
    939. 935
    940. 936
    941. 937
    942. 938
    943. 939
    944. 940
    945. 941
    946. 942
    947. 943
    948. 944
    949. 945
    950. 946
    951. 947
    952. 948
    953. 949
    954. 950
    955. 951
    956. 952
    957. 953
    958. 954
    959. 955
    960. 956
    961. 957
    962. 958
    963. 959
    964. 960
    965. 961
    966. 962
    967. 963
    968. 964
    969. 965
    970. 966
    971. 967
    972. 968
    973. 969
    974. 970
    975. 971
    976. 972
    977. 973
    978. 974
    979. 975
    980. 976
    981. 977
    982. 978
    983. 979
    984. 980
    985. 981
    986. 982
    987. 983
    988. 984
    989. 985
    990. 986
    991. 987
    992. 988
    993. 989
    994. 990
    995. 991
    996. 992
    997. 993
    998. 994
    999. 995
    1000. 996
    1001. 997
    1002. 998
    1003. 999
    1004. TERMINATED

    展示Blocked, Waiting, TimedWaiting线程状态代码演示:
    1. /**
    2. * 描述: 展示Blocked, Waiting, TimedWaiting
    3. */
    4. public class BlockedWaitingTimedWaiting implements Runnable{
    5. public static void main(String[] args) {
    6. BlockedWaitingTimedWaiting runnable = new BlockedWaitingTimedWaiting();
    7. Thread thread1 = new Thread(runnable);
    8. thread1.start();
    9. Thread thread2 = new Thread(runnable);
    10. thread2.start();
    11. try {
    12. Thread.sleep(5);
    13. } catch (InterruptedException e) {
    14. e.printStackTrace();
    15. }
    16. //打印出Timed_Waiting状态,因为正在执行Thread.sleep(1000);
    17. System.out.println(thread1.getState());
    18. //打印出BLOCKED状态,因为thread2想拿得到sync()的锁却拿不到
    19. System.out.println(thread2.getState());
    20. try {
    21. Thread.sleep(1300);
    22. } catch (InterruptedException e) {
    23. e.printStackTrace();
    24. }
    25. //打印出WAITING状态,因为执行了wait()
    26. System.out.println(thread1.getState());
    27. }
    28. @Override
    29. public void run() {
    30. syn();
    31. }
    32. private synchronized void syn() {
    33. try {
    34. Thread.sleep(1000);
    35. wait();
    36. } catch (InterruptedException e) {
    37. e.printStackTrace();
    38. }
    39. }
    40. }

    运行结果:

    1. TIMED_WAITING
    2. BLOCKED
    3. WAITING

    2.4.2、阻塞状态

    2.4.3、面试题

    线程有哪几种状态?生命周期是什么?

    2.5、核心5:Thread和Object类中的重要方法详解

    主要方法

    1、为什么线程通信的方法wait(),notify()和notifyAll()被定义在Object类里面?而sleep定义在了Thread类中?
    2、用3中方式实现生产者模式
    3、java se 8 和java 1.8 和jdk 8是什么关系,是同一个东西吗?
    4、join和sleep和wait期间线程的状态分别是什么?为什么?

    2.5.1、wait方法

    阻塞阶段
    wait
    一个线程或者多个线程暂时休息,等到后续需要时再唤醒。
    执行wait方法时,必须先拥有对象的monitor锁,调用wait方法之后,调用这个方法的线程进入阻塞状态,不参与线程的调度,直到以下4种情况之一发生时,才会被唤醒。
    1)另一个线程调用这个对象的notify()方法且刚好被唤醒的是本线程(notify只唤醒一个线程)
    2)另外一个线程调用这个对象的notifyAll()方法。
    3)过了wait(long timeout)规定的超时时间,如果传入为0就是永久等待。
    4)线程自身调用了interrupt()。
    
    唤醒阶段
    notify:唤醒单个正在等待某对象monitor的线程,唤醒时,如果有多个线程都在等待,选择其中一个唤醒(具体的唤醒选择任意的,Java对此没有一个严格的规范,JVM可以拥有自己的实现)。
    notify和wait都需要在synchronized关键字保护的方法或者代码块中执行,在外面执行的话,会抛出异常
    notifyAll:唤醒所有等待的线程。
    遇到中断
    假设线程执行了wait方法,在此期间如果被中断,会抛出InterruptedException,释放掉已经获取到的monitor。

    wait和notify的基本用法代码演示:

    1. /**
    2. * 描述: 展示wait和notify的基本用法
    3. * 1. 研究代码执行顺序
    4. * 2. 证明wait释放锁
    5. */
    6. public class Wait {
    7. public static Object object = new Object();
    8. static class Thread1 extends Thread {
    9. @Override
    10. public void run() {
    11. synchronized (object) {
    12. System.out.println(Thread.currentThread().getName() + "开始执行了");
    13. try {
    14. object.wait();
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. System.out.println("线程" + Thread.currentThread().getName() + "获取到了锁。");
    19. }
    20. }
    21. }
    22. static class Thread2 extends Thread {
    23. @Override
    24. public void run() {
    25. synchronized (object) {
    26. object.notify();
    27. System.out.println("线程" + Thread.currentThread().getName() + "调用了notify()");
    28. }
    29. }
    30. }
    31. public static void main(String[] args) throws InterruptedException {
    32. Thread1 thread1 = new Thread1();
    33. Thread2 thread2 = new Thread2();
    34. thread1.start();
    35. Thread.sleep(200);
    36. thread2.start();
    37. }
    38. }

    运行结果:

    1. Thread-0开始执行了
    2. 线程Thread-1调用了notify()
    3. 线程Thread-0获取到了锁。

    代码演示:3个线程,线程1和线程2首先被阻塞,线程3唤醒它们。notify, notifyAll。 start先执行不代表线程先启动。
    1. /**
    2. * 描述: 3个线程,线程1和线程2首先被阻塞,线程3唤醒它们。
    3. * notify, notifyAll。
    4. * start先执行不代表线程先启动。
    5. */
    6. public class WaitNotifyAll implements Runnable {
    7. private static final Object resourceA = new Object();
    8. public static void main(String[] args) throws InterruptedException {
    9. Runnable r = new WaitNotifyAll();
    10. Thread threadA = new Thread(r);
    11. Thread threadB = new Thread(r);
    12. Thread threadC = new Thread(new Runnable() {
    13. @Override
    14. public void run() {
    15. synchronized (resourceA) {
    16. resourceA.notifyAll();
    17. // resourceA.notify();
    18. System.out.println("ThreadC notified.");
    19. }
    20. }
    21. });
    22. threadA.start();
    23. threadB.start();
    24. Thread.sleep(200);
    25. threadC.start();
    26. }
    27. @Override
    28. public void run() {
    29. synchronized (resourceA) {
    30. System.out.println(Thread.currentThread().getName()+" got resourceA lock.");
    31. try {
    32. System.out.println(Thread.currentThread().getName()+" waits to start.");
    33. resourceA.wait();
    34. System.out.println(Thread.currentThread().getName()+"'s waiting to end.");
    35. } catch (InterruptedException e) {
    36. e.printStackTrace();
    37. }
    38. }
    39. }
    40. }

    运行结果:

    1. Thread-0 got resourceA lock.
    2. Thread-0 waits to start.
    3. Thread-1 got resourceA lock.
    4. Thread-1 waits to start.
    5. ThreadC notified.
    6. Thread-0's waiting to end.
    7. Thread-1's waiting to end.

    1. /**
    2. * 描述: 3个线程,线程1和线程2首先被阻塞,线程3唤醒它们。
    3. * notify, notifyAll。
    4. * start先执行不代表线程先启动。
    5. */
    6. public class WaitNotifyAll implements Runnable {
    7. private static final Object resourceA = new Object();
    8. public static void main(String[] args) throws InterruptedException {
    9. Runnable r = new WaitNotifyAll();
    10. Thread threadA = new Thread(r);
    11. Thread threadB = new Thread(r);
    12. Thread threadC = new Thread(new Runnable() {
    13. @Override
    14. public void run() {
    15. synchronized (resourceA) {
    16. // resourceA.notifyAll();
    17. resourceA.notify();
    18. System.out.println("ThreadC notified.");
    19. }
    20. }
    21. });
    22. threadA.start();
    23. threadB.start();
    24. Thread.sleep(200);
    25. threadC.start();
    26. }
    27. @Override
    28. public void run() {
    29. synchronized (resourceA) {
    30. System.out.println(Thread.currentThread().getName()+" got resourceA lock.");
    31. try {
    32. System.out.println(Thread.currentThread().getName()+" waits to start.");
    33. resourceA.wait();
    34. System.out.println(Thread.currentThread().getName()+"'s waiting to end.");
    35. } catch (InterruptedException e) {
    36. e.printStackTrace();
    37. }
    38. }
    39. }
    40. }

    运行结果:

    1. Thread-0 got resourceA lock.
    2. Thread-0 waits to start.
    3. ThreadC notified.
    4. Thread-1 got resourceA lock.
    5. Thread-1 waits to start.
    6. Thread-0's waiting to end.

    wait只释放当前的那把锁,不同的锁之间相互独立。

    代码演示:

    1. /**
    2. * 描述: 证明wait只释放当前的那把锁
    3. */
    4. public class WaitNotifyReleaseOwnMonitor {
    5. private static volatile Object resourceA = new Object();
    6. private static volatile Object resourceB = new Object();
    7. public static void main(String[] args) {
    8. Thread thread1 = new Thread(new Runnable() {
    9. @Override
    10. public void run() {
    11. synchronized (resourceA) {
    12. System.out.println("ThreadA got resourceA lock.");
    13. synchronized (resourceB) {
    14. System.out.println("ThreadA got resourceB lock.");
    15. try {
    16. System.out.println("ThreadA releases resourceA lock.");
    17. resourceA.wait();
    18. } catch (InterruptedException e) {
    19. e.printStackTrace();
    20. }
    21. }
    22. }
    23. }
    24. });
    25. Thread thread2 = new Thread(new Runnable() {
    26. @Override
    27. public void run() {
    28. try {
    29. Thread.sleep(1000);
    30. } catch (InterruptedException e) {
    31. e.printStackTrace();
    32. }
    33. synchronized (resourceA) {
    34. System.out.println("ThreadB got resourceA lock.");
    35. System.out.println("ThreadB tries to resourceB lock.");
    36. synchronized (resourceB) {
    37. System.out.println("ThreadB got resourceB lock.");
    38. }
    39. }
    40. }
    41. });
    42. thread1.start();
    43. thread2.start();
    44. }
    45. }

    运行结果:

    1. ThreadA got resourceA lock.
    2. ThreadA got resourceB lock.
    3. ThreadA releases resourceA lock.
    4. ThreadB got resourceA lock.
    5. ThreadB tries to resourceB lock.

    wait、notify、notifyAll特点、性质
    1、必须先拥有monitor
    2、notify只能唤醒一个 ,唤醒哪个线程取决于JVM的实现
    3、属于Object类
    4、类似功能的Condition
    5、同时拥有多个锁的情况(只会释放现在wait所对应的对象的那把锁,如果对象持有多把锁,注意释放顺序,否则会发生死锁)

     

     

     

    重点:使用wait/notify实现生产者消费者设计模式

     

     

    代码演示:

    1. import java.util.Date;
    2. import java.util.LinkedList;
    3. /**
    4. * 描述: 用wait/notify来实现生产者消费者模式
    5. * 思路参考自Java concurrency Cookbook Using conditions in synchronized code
    6. */
    7. public class ProducerConsumerModel {
    8. public static void main(String[] args) {
    9. EventStorage eventStorage = new EventStorage();
    10. Producer producer = new Producer(eventStorage);
    11. Consumer consumer = new Consumer(eventStorage);
    12. new Thread(producer).start();
    13. new Thread(consumer).start();
    14. }
    15. }
    16. class Producer implements Runnable {
    17. private EventStorage storage;
    18. public Producer(
    19. EventStorage storage) {
    20. this.storage = storage;
    21. }
    22. @Override
    23. public void run() {
    24. for (int i = 0; i < 100; i++) {
    25. storage.put();
    26. }
    27. }
    28. }
    29. class Consumer implements Runnable {
    30. private EventStorage storage;
    31. public Consumer(
    32. EventStorage storage) {
    33. this.storage = storage;
    34. }
    35. @Override
    36. public void run() {
    37. for (int i = 0; i < 100; i++) {
    38. storage.take();
    39. }
    40. }
    41. }
    42. class EventStorage {
    43. private int maxSize;
    44. private LinkedList storage;
    45. public EventStorage() {
    46. maxSize = 10;
    47. storage = new LinkedList<>();
    48. }
    49. public synchronized void put() {
    50. while (storage.size() == maxSize) {
    51. try {
    52. wait();
    53. } catch (InterruptedException e) {
    54. e.printStackTrace();
    55. }
    56. }
    57. storage.add(new Date());
    58. System.out.println("仓库里有了" + storage.size() + "个产品。");
    59. notify();
    60. }
    61. public synchronized void take() {
    62. while (storage.size() == 0) {
    63. try {
    64. wait();
    65. } catch (InterruptedException e) {
    66. e.printStackTrace();
    67. }
    68. }
    69. System.out.println("拿到了" + storage.poll() + ",现在仓库还剩下" + storage.size());
    70. notify();
    71. }
    72. }

  • 相关阅读:
    Mybatis-Plus复习
    技术保证质量,软件测试的这些测试方法你都掌握了吗?
    数据分析大作战,SQL V.S. Python,来看看这些考题你都会吗 ⛵
    vim编辑器常用插件安装及配色方案
    【JVM】三色标记法
    这些嵌入式系统安全性的知识你需要了解
    NET框架程序设计-第4章类型基础
    快学会这个技能-.NET API拦截技法
    单点登录SSO
    Zabbix5.0配置企业微信告警
  • 原文地址:https://blog.csdn.net/Xx13624558575/article/details/126916047