1、写一个包子生产消费案例:一次生产或消费一个包子,有包子就消费,没有就生产。(部分代码参考传智播客刘意2015Java基础视频讲义)

1.1 写一个Baozi.class,包含main()方法,用来测试

  1. package com.oy.demo3;
  2.  
  3. /*
  4. * 包子生产消费案例:一次生产或消费一个包子,有包子就消费,没有就生产。
  5. */
  6. public class Baozi {
  7. // 默认是flag,表示没有包子,需要生产线程来生产包子;如果是true,说明有包子,需要消费端来消费包子。
  8. public boolean flag;
  9.  
  10. // 计数,当前在生产或消费第n个包子
  11. public int count = 0;
  12.  
  13. public static void main(String[] args) {
  14. // 创建共享对象
  15. Baozi s = new Baozi();
  16.  
  17. // 在外界把共享对象创建出来,通过构造方法传递给其他的类。这样st、gt1、gt2就共享s对象。
  18. SetThread st = new SetThread(s);
  19. GetThread gt1 = new GetThread(s);
  20. GetThread gt2 = new GetThread(s);
  21.  
  22. // 线程类
  23. Thread t1 = new Thread(st);
  24. Thread t2 = new Thread(gt1);
  25. Thread t3 = new Thread(gt2);
  26.  
  27. // 启动线程
  28. t1.start();
  29. t2.start();
  30. t3.start();
  31. }
  32. }

1.2 生产包子的线程类 SetThread.class

  1. package com.oy.demo3;
  2.  
  3. public class SetThread implements Runnable {
  4. private Baozi s;
  5.  
  6. public SetThread(Baozi s) {
  7. this.s = s;
  8. }
  9.  
  10. @Override
  11. public void run() {
  12. while (true) {
  13. synchronized (s) {
  14. // 判断有没有
  15. if (s.flag) { // 生产端,有就等待
  16. try {
  17. System.out.println("生产端:等待。。。");
  18. s.wait(); // 等待,并且立即释放锁。将来醒过来的时候,是从这里醒过来的
  19. System.out.println("生产端:醒过来了。。。");
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24.  
  25. // 开始生产
  26. s.count++;
  27. System.out.println("生产第" + s.count + "包子。。。");
  28.  
  29. // 生产完后,修改标记为true
  30. s.flag = true;
  31. // 唤醒线程
  32. s.notifyAll();
  33. System.out.println("==========开始抢CPU的执行权==========");
  34. }
  35. }
  36. }
  37. }

1.3 消费包子的线程类 GetThread.class

  1. package com.oy.demo3;
  2.  
  3. public class GetThread implements Runnable {
  4. private Baozi s;
  5.  
  6. public GetThread(Baozi s) {
  7. this.s = s;
  8. }
  9.  
  10. @Override
  11. public void run() {
  12. while (true) {
  13. synchronized (s) {
  14. while (!s.flag) { // 消费端,没有就等待
  15. try {
  16. System.out.println(Thread.currentThread().getName() + "消费端:等待。。。");
  17. s.wait(); // 等待,并且立即释放锁。将来醒过来的时候,是从这里醒过来的
  18. System.out.println(Thread.currentThread().getName() + "消费端:醒过来了。。。");
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23.  
  24. // 开始消费
  25. System.out.println(Thread.currentThread().getName() + "消费第" + s.count + "个包子");
  26.  
  27. // 消费完了,修改标记为false
  28. s.flag = false;
  29. // 唤醒线程
  30. s.notifyAll();
  31. System.out.println("==========开始抢CPU的执行权==========");
  32. }
  33. }
  34. }
  35. }

2、测试结果(只选择了控制台打印的部分结果):

  1. ==========开始抢CPU的执行权==========
  2. 生产端:等待。。。
  3. Thread-2消费端:醒过来了。。。
  4. Thread-2消费第6806个包子 // Thread-2消费完了第6806个包子,然后唤醒等待的线程;
  5. ==========开始抢CPU的执行权========== // 然后3个线程开始抢CPU的执行权
  6. Thread-2消费端:等待。。。        // 消费端线程Thread-2抢到了,但是此时没有包子了,所以等待
  7. Thread-1消费端:醒过来了。。。      // 然后,消费端线程Thread-1抢到了执行权,在原来wait()方法的地方醒过来,
                          // 执行wait()方法后面的代码System.out.println(Thread.currentThread().getName() + "消费端:醒过来了。。。")
  8. Thread-1消费端:等待。。。        // 然后继续while循环判断,由于此时没有包子,所以等待;
                          // 如果把while改成if,就不会判断是否有包子,直接执行后面的代码消费包子,
                          // 此时并没有包子了,这就产生了错误(同一个包子被消费了两次)。
  9. 生产端:醒过来了。。。
  10. 生产第6807包子。。。
  11. ==========开始抢CPU的执行权==========

3、对测试结果的分析:

  3.1 首先明确,生产端开启了一个线程,消费端开启了两个线程。

  3.2 Thread-2消费完了第6806个包子,然后唤醒等待的线程;然后3个线程开始抢CPU的执行权,消费端线程Thread-2抢到了,但是此时没有包子了,所以等待;

  3.3 然后,消费端线程Thread-1抢到了执行权,在原来wait()方法的地方醒过来,执行wait()方法后面的代码System.out.println(Thread.currentThread().getName() + "消费端:醒过来了。。。"),然后继续while循环判断,由于此时没有包子,所以等待。如果把while改成if,就不会判断是否有包子,直接执行后面的代码消费包子,此时并没有包子了,这就产生了错误(同一个包子被消费了两次)。

  3.4 综上所述:wait()方法套在while循环中,线程下次醒过来后会继续进行循环,判断条件是否满足,满足就重新等待。

  3.5 由于生产端只开启了一个线程,所以将wait()方法套在if代码块中也是可以的,当然使用while也可以。

java多线程wait()方法必须放在while循环里面的原因探析的更多相关文章

  1. Java 多线程 sleep方法与wait方法的区别

    sleep方法会使线程暂停执行一段时间,wait方法会阻塞线程,直到被唤醒或等待时间超时. 两者区别具体如下: 1 原理不同 sleep方法是Thread类的静态方法,使线程暂停执行一段时间,等到计时 ...

  2. Java多线程-run方法与start方法的区别

    package com.interview; /** * java多线程的两种实现方式以及run.start方法的区别 * @author MEI.LIU * */ public class Thre ...

  3. Java多线程-join方法

    thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程.比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B. 具体例子看链接 ...

  4. Java——多线程之方法详解

    Java多线程系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多 ...

  5. Java多线程优化方法及使用方式

    一.多线程介绍 在编程中,我们不可逃避的会遇到多线程的编程问题,因为在大多数的业务系统中需要并发处理,如果是在并发的场景中,多线程就非常重要了.另外,我们在面试的时候,面试官通常也会问到我们关于多线程 ...

  6. java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解

    synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...

  7. java多线程 join方法以及优先级方法

    /*join:当A线程执行到了B线程的.join()方法时,A就会等待.等B线程都执行完,A才会执行. join可以用来临时加入线程执行. 1.线程使用join方法,主线程就停下,等它执行完,那么如果 ...

  8. 2017第45周一java多线程创建方法

    1. 从JDK1.5开始,Java提供了3种方式来创建,启动多线程: Ø 继承Thread类来创建线程类,重写run()方法作为线程执行体. Ø 实现Runnable接口来创建线程类,重写run()方 ...

  9. Java 多线程 interrupt方法

    interrupt 下面是interrupt方法的文档的一部分: * <p> If this thread is blocked in an invocation of the {@lin ...

随机推荐

  1. (转)ResNet, AlexNet, VGG, Inception: Understanding various architectures of Convolutional Networks

    ResNet, AlexNet, VGG, Inception: Understanding various architectures of Convolutional Networks by KO ...

  2. Python3 list sort排序

    转自:https://blog.csdn.net/u010758410/article/details/79737498 当带排序列表的元素由多字段构成时,我们可以通过sorted(iterable ...

  3. Facebook ads_Business Manager

    xmind 下载链接

  4. postgresql:array & foreach

    --数组: SELECT (ARRAY['{101, 111, 121}', '{201, 211, 221}'])[1]::text[]; SELECT (ARRAY['{101, 111, 121 ...

  5. python爬虫训练——爬poj题目

    首先要解决的就是不同的题目在不同的页上,也就是要实现翻页功能,自动获取所要爬取的地址,通过分析可以得出不同的页面也就是volume=后面的数字不同 所以我们可以用re模块来替换即可: new_url ...

  6. HDU 5754 Life Winner Bo(各类博弈大杂合)

    http://acm.hdu.edu.cn/showproblem.php?pid=5754 题意: 给一个国际象棋的棋盘,起点为(1,1),终点为(n,m),现在每个棋子只能往右下方走,并且有4种不 ...

  7. React内三种函数的写法

     以下提供三种React内函数的写法,都可以正常运行,有疑问可以留言 写法一:让函数内部的this指向这个类的实例,它是用bind实现的,bind的第一个参数表示context,就是this. //写 ...

  8. Python 爬虫常用的库

    一.常用库 1.requests 做请求的时候用到. requests.get("url") 2.selenium 自动化会用到. 3.lxml 4.beautifulsoup 5 ...

  9. P3110 [USACO14DEC]驮运Piggy Back

    传送门 做过次短路后,再来做这题感觉轻松不少. 这题看着就像最短路模板题. 思路: 虽说题目看起来比较水,但是码起来还是有点难度的.(对我这个蒟蒻来说) 这道题,跟"路障"一题差不 ...

  10. 《spring boot 实战》读书笔记

    前言:虽然已经用spring boot开发过一套系统,但是之前都是拿来主义,没有系统的,全面的了解过这套框架.现在通过学习<spring boot实战>这本书,希望温故知新.顺便实现自己的 ...