java线程间通信:一个小Demo完全搞懂

小说:微信赚钱群是真的假的作者:邓伯王乙更新时间:2018-12-15字数:44244

叶扬耸耸肩说道:“就那四个家伙,真是太菜了,你们堂堂的大曰本鬼子国怎么就出了这几个破玩意,连一招都没走过就全挂了”。

网上兼职怎么做

又不是相互克制反而是同出一源的情况下如果不是压倒性的实力是很难将索克摧毁的。
千仞雪看到的,是唐三那执着而充满了无尽霸气的血色双眸。哪怕是在面对自己这样的神,他的战意也丝毫没有减弱的意思。千仞雪不明白唐三是怎么做到的。但是,她却不得不再次抬起双手,架住了唐三这一击。而这一次,她的身体更是被硬生生地砸向了地面。

卡普看着远去的两艘船,本来他已经决定了不管艾斯最后有没有被救走他都会辞职了,夹在中间实在是太辛苦了,不过现在看到新的势力出现了,他觉得也挺有意思的,在目前看来比起世界政府要好多了,而现在艾斯也被救走了,随着刘皓一条公告下来他也没有任何心理负担,所以他也决定继续留下来看看先。

java线程间通信:一个小Demo完全搞懂


版权声明:本文出自汪磊的博客,转载请务必注明出处。

Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过。

一、从一个小Demo说起

上篇我们聊到了Java多线程的同步机制:Java多线程同步问题:一个小Demo完全搞懂。这篇我们聊一下java多线程之间的通信机制。

上一篇探讨java同步机制的时候我们举得例子输出log现象是:一段时间总是A线程输出而另一段时间总是B线程输出,有没有一种方式可以控制A,B线程交错输出呢?答案是当然可以了,这时候我们就要用到多线程的wait/notify机制了。

wait/notify机制就是当线程A执行到某一对象的wait()方法时,就会进入等待状态,此时线程A放弃持有的锁,其余线程可以竞争锁的持有权。当有其余线程调用notify()或者notifyAll()方法的时候就可能(当有多个线程的时候notify()方法只会唤醒处于等待状态线程中的一个)唤醒线程A,使其从wait状态醒来,继续向下执行业务逻辑。

接下来,我们通过一个小demo加以理解。

二、单生产者消费者模式

demo很简单,就是开启两个线程,一个生产面包,另一个负责消费面包,并且生产一个就要消费一个,交替执行。

首先看下BreadFactory类:

 1 public class BreadFactory {
 2     //生产面包个数计数器
 3     private int count = 0;
 4     //线程的锁
 5     private Object o = new Object();
 6     private boolean flag = false;
 7 
 8     public void product() {
 9         synchronized (o) {
10             if (flag) {
11                 try {
12                     o.wait();
13                 } catch (InterruptedException e) {
14                     e.printStackTrace();
15                 }
16             }
17             try {
18                 Thread.sleep(2000);
19             } catch (InterruptedException e) {
20                 e.printStackTrace();
21             }
22             System.out.println(Thread.currentThread().getName()+"生产了第" + (++count) + "个面包");
23             flag = true;
24             o.notify();
25         }
26     }
27 
28     public void consume() {
29         synchronized (o) {
30             if (!flag) {
31                 try {
32                     o.wait();
33                 } catch (InterruptedException e) {
34                     e.printStackTrace();
35                 }
36             }
37             try {
38                 Thread.sleep(2000);
39             } catch (InterruptedException e) {
40                 e.printStackTrace();
41             }
42             System.out.println(Thread.currentThread().getName()+"消费第" + count + "个面包");
43             flag = false;
44             o.notify();
45         }
46     }
47 }

此类就是负责生产,消费面包,flag主要用于控制线程之间的切换。

接下来我们看下Producter,Consumer类:

 1 public class Producter extends Thread {
 2 
 3     private BreadFactory mBreadFactory;
 4 
 5     public Producter(BreadFactory mBreadFactory) {
 6         super();
 7         this.mBreadFactory = mBreadFactory;
 8     }
 9     
10     @Override
11     public void run() {
12         //
13         while (true) {
14             mBreadFactory.product();
15         }
16     }    
17 }

很简单,初始化的时候需要传递进来一个BreadFactory实例对象,线程启动的时候调用BreadFactory类中product()方法不停生产面包。

Consumer类同理:

 1 public class Consumer extends Thread {
 2 
 3     private BreadFactory mBreadFactory;
 4 
 5     public Consumer(BreadFactory mBreadFactory) {
 6         super();
 7         this.mBreadFactory = mBreadFactory;
 8     }
 9     
10     @Override
11     public void run() {
12         //
13         while (true) {
14             mBreadFactory.consume();
15         }
16     }
17 }

最后看下main方法:

1 public static void main(String[] args) {
2         //
3         BreadFactory factory = new BreadFactory();
4         Producter p1 = new Producter(factory);
5         p1.start();
6         Consumer c1 = new Consumer(factory);
7         c1.start();
8 }

没什么要多说的,就是初始化并启动线程,运行程序,输出如下:

Thread-0生产了第1个面包
Thread-1消费第1个面包
Thread-0生产了第2个面包
Thread-1消费第2个面包
Thread-0生产了第3个面包
Thread-1消费第3个面包
Thread-0生产了第4个面包
Thread-1消费第4个面包
。。。。。

三、多生产者消费者模式

似乎很顺利的就实现了啊,但是实际需求中怎么可能只有一个生产者,一个消费者,生产者,消费者是有多个的,我们试下多个生产者,消费者是什么现象,修改main中逻辑:

 1 public static void main(String[] args) {
 2         //
 3         BreadFactory factory = new BreadFactory();
 4         Producter p1 = new Producter(factory);
 5         p1.start();
 6         Consumer c1 = new Consumer(factory);
 7         c1.start();
 8         Producter p2 = new Producter(factory);
 9         p2.start();
10         Consumer c2 = new Consumer(factory);
11         c2.start();
12 }

我们就是只多添加了一个生产者和一个消费者,其余没任何变化。

运行程序,输出信息如下:

。。。
Thread-2生产了第4个面包
Thread-1消费第4个面包
Thread-2生产了第5个面包
Thread-1消费第5个面包
Thread-2生产了第6个面包
Thread-1消费第6个面包
Thread-3消费第6个面包
Thread-0生产了第7个面包
Thread-3消费第7个面包
。。。

咦?生产到第6个面包,竟然被消费了两次,这显然是不正常的,那是哪里出问题了呢?

四、多生产者消费者模式问题产生原因分析

接下来,我们直接分析问题产生的原因,我们分析下BreadFactory中product()与consume()方法:

 1 public void product() {
 2         synchronized (o) {
 3             if (flag) {
 4                 try {
 5                     o.wait();
 6                 } catch (InterruptedException e) {
 7                     e.printStackTrace();
 8                 }
 9             }
10             try {
11                 Thread.sleep(100);
12             } catch (InterruptedException e) {
13                 e.printStackTrace();
14             }
15             System.out.println(Thread.currentThread().getName()+"生产了第" + (++count) + "个面包");
16             flag = true;
17             o.notify();
18         }
19     }
20 
21     public void consume() {
22         synchronized (o) {
23             if (!flag) {
24                 try {
25                     o.wait();
26                 } catch (InterruptedException e) {
27                     e.printStackTrace();
28                 }
29             }
30             try {
31                 Thread.sleep(100);
32             } catch (InterruptedException e) {
33                 e.printStackTrace();
34             }
35             System.out.println(Thread.currentThread().getName()+"消费第" + count + "个面包");
36             flag = false;
37             o.notify();
38         }
39     }

从线程启动顺序以及打印信息可以看出线程0,线程2负责生产面包,线程1,线程3负责消费面包。

线程执行过程中,线程1消费掉第5个面包,此时flag置为false,执行notify()方法唤醒其余线程争取锁获取执行权。

此时线程3获取线程执行权,执行consume()业务逻辑flag此时为false,进入if(!flag)逻辑,执行wait()方法,此时线程3进入wait状态,停留在25行代码处。释放锁资源,其余线程可以争取执行权。

此时线程1获取执行权,和线程3一样,最终停留在25行代码处释放锁资源,其余线程可以争取执行权。注意:此时线程1,线程3都停留在25行代码处,处于wait状态。

接下来线程2获取执行权,执行生产业务,生产了第6个面包,然后释放锁资源,其余线程可以争取执行权。

然后线程1又获取执行权,上面说了线程1停留在25行代码处,现在获取执行权从25行代码处开始执行,消费掉第6个面包没问题,flag置为false。然后释放锁资源,其余线程可以争取执行权。

此时线程3又获取执行权,上面分析时说了线程3处于25行代码处wait状态,现在获取执行权从25行代码处开始执行,又消费了第6个面包,到这里面包6被消耗了两次。

经过上面分析已经知道产生问题的原因了,线程获取执行权后直接从wait处开始继续执行,不在检查if条件是否成立,这里就是问题产生的原因了。

那怎么修改的呢?很简单了,将if判断改为while条件判断就可以了,这样线程获取执行权后还会再次检查while条件判断是否成立。

运行程序打印Log如下:

1 。。。
2 Thread-1消费第19个面包
3 Thread-0生产了第20个面包
4 Thread-1消费第20个面包
5 Thread-2生产了第21个面包

看输出Log上面问题是解决了,生产一个面包只会消费一次,但是发现程序运行自己终止了,上面生产到第21个面包程序似乎不运行了没Log输出了,这是什么原因呢?

五、notify()通知丢失问题以及notify()与notifyAll()的区别

要想明白上述问题产生的原因我们就必须搞懂notify()与notifyAll()的区别。简单说就是notify()只会唤醒同一监视器处于wait状态的一个线程(随机唤醒),

雅米兼职是正规平台吗 赚客吧注册 找农村养殖合作项目 网络投资好项目 蜂箱在淘宝属于什么主营项目 东方头条自媒体赚钱吗 关于花生日记如何赚钱 爱疯x多少钱

编辑:顺卓

我要说两句: (0人参与)

发布