序:线程之间的通信,是多线程之间普遍存在的方法,接下来,我就根据自己所学,来一一讲解一下:
线程之间的通信
一、为什么要线程通信?
1. 多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,
并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。
2.当然如果我们没有使用线程通信来使用多线程共同操作同一份数据的话,虽然可以实现,
但是在很大程度会造成多线程之间对同一共享变量的争夺,那样的话势必为造成很多错误和损失!
3.所以,我们才引出了线程之间的通信,
二、什么是线程通信?
多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。
就是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。
于是我们引出了等待唤醒机制:(wait()、notify())
就是在一个线程进行了规定操作后,就进入等待状态(wait), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify);
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。
线程调用wait()方法,释放它对锁的拥有权,然后等待另外的线程来通知它(通知的方式是notify()或者notifyAll()方法),这样它才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁,即,wait()方法的调用必须放在synchronized方法或synchronized块中。
(2)notif()方法:
三、实现线程通信的小demo
如大众所说,体现线程通信的鲜明的例子:生产者---消费者是最明显的例子之一。那我们接下来敲一个关于生产者和消费者的简单的小demo,来演示一下线程的通信:
(1)面包的类(生产和消费方法都在里面哦)
/ *@functon 线程通信之面包类 *@author 温煦(昵称:沉沦之巅) *@time 2017.12.5 */ package ThreadMessage; public class Breads { //面包的id private int bid; //面包的个数 private int num; //生产面包的方法(由于是demo,方便大家理解,就把synchronized关键字加到方法上面了哦) public synchronized void produc(){ //当面包的数量不为0时,该方法处于等待状态 if(0 != num){ try { wait();//等待 } catch (InterruptedException e) { e.printStackTrace(); } } //当面包数量为0时,那么就开始生产面包了哦 num = num +1;//数量加1 bid = bid + 1 ;//id当然也得加1 String threadname = Thread.currentThread().getName(); System.out.println(threadname+"生产了一个编号为"+bid+"的面包!"); notify();//当执行完后,去唤醒其他处于等待的线程 } //消费面包的方法 public synchronized void consume(){ //当面包的数量为0时,该方法处于等待状态 if(num == 0 ){ try { wait();//等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //消费完面包了,所以面包数量降为0了 num = num -1;//数量减1 String name1 = Thread.currentThread().getName(); System.out.println(name1+"买了一个面包编号为"+bid); notify();//当执行完后,去唤醒其他处于等待的线程 } //set和get方法 public int getBid() { return bid; } public void setBid(int bid) { this.bid = bid; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } //有参构造 public Breads(int bid, int num) { super(); this.bid = bid; this.num = num; } //无参构造 public Breads() { super(); // TODO Auto-generated constructor stub } }
(2)生产面包的类
(3)消费面包的类
(4)测试类
(5)演示效果(因数据太多,中间就省略了哦)
如上所示,案例表明生产者消费者之间就是运用了wait()和notify()这两个方法,通过通信的沉睡与唤醒机制来完成两个不同线程操作统一数据之间的通信,
当生产者生产出一个面包时,就会陷入沉睡,随后立即去唤醒消费者,就像是对他说,你去买吧,我生产好了,然后消费者就会屁颠屁颠的去买了那个面包,当他吃完那个面包后,
也会陷入沉睡,随后立即唤醒生产者,就像是对他说,你再生产一个吧,我吃完了,然后生产者就... ... 如此循环,周而复始,直到for循环结束为止。
四、多个生产者和消费者
当我们创建多个生产者和消费者时,上述的代码就会出现一个问题,就是他们无法直到到底要唤醒哪一个,所以这时候我们就用到了
那么代码就不一一再发了,与上面的差不多,唯一不一样的就是在面包类里的if换成while循环判断,notif()换成notifAll()。
然后再给大家写一下多个生产者和消费者的测试类:
(1)多个生产者和消费者的测试类
(2)演示多个生产者和消费者通信效果
如上所示,我们创建了三个生产者和三个消费者,所以我们for循环为三次,也就是会生产和消费各60个面包;
当进程开始后,会随机开启一个生产者线程生产一个面包后,陷入沉睡,随后会随机唤醒一个消费者线程,
接着消费掉刚刚生产的那个面包,再次陷入沉睡,随机唤醒一个生产者线程... 周而复始,直到结束。
结束语:今天的线程通信通信就到这里了,如果你还有什么疑问可以随时联系我,当然非常希望阅读了本篇文章的读者,都能得到帮助,
最后祝愿各位在以后线程的学习道路上芝麻开花节节高。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/1005.html