Java学习day48-线程的通信,生产者与消费者
一、线程通信
1.wait()与notify()和notifyAll()
①wait():令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问。
②notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待。
③notifyAll():唤醒正在排队等待资源的所有线程结束等待。
2.Java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.lllegalMonitorStateException异常。
3.这三个方法只能用在有同步锁的方法或者代码块中。
二、wait()方法
1.在当前线程中调用方法:对象名.wait()
2.使当前线程进入等待(某对象)状态,直到另一线程对该对发出notify(或notifyAll)为止。
3.调用方法的必要条件:当前线程必须具有该对象监控权(加锁)。
4.调用此方法后,当前线程将释放对象监控权,然后进入等待。
5.在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
三、notify()/notifyAll()
1.在当前线程中调用方法:对象名.notify()
2.功能:唤醒等待该对象监控权的一个线程。
3.调用方法的必要条件:当前线程必须具有该对象监控权(加锁)。
package day20; public class Test2 { public static void main(String[] args){ //定义账户对象 Acount a = new Acount(); Acount a1 = new Acount(); //多线程对象 User u_weixin = new User(a,2000); User u_zhifubao = new User(a,2000); Thread weixin = new Thread(u_weixin,"微信"); Thread zhifubao = new Thread(u_zhifubao,"支付宝"); weixin.start(); zhifubao.start(); } } class Acount{ public static int money = 3000; public synchronized void drawing5(int m,Acount a){ synchronized(a){//表示通过方法的参数传递进来的对象的代码块,被加了synchronized同步锁 //不同的对象就有了不同的同步锁 String name = Thread.currentThread().getName(); //需求:如果是微信操作的,先不执行,等支付宝操作,支付宝操作完,微信再继续操作 if(name.equals("微信")){ try { a.wait();//当前线程进入等待的阻塞状态 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(money < m){ System.out.println(name + "操作,账户金额不足:" + money); }else{ System.out.println(name + "操作,账户原有金额:" + money); System.out.println(name +"操作,取款金额:" + m); System.out.println(name +"操作,取款操作:原金额" + money + "-" +"取款金额" + m); money = money - m; System.out.println(name +"操作,账户取款后余额:" + money); } if(name.equals("支付宝")){ a.notify();//唤醒当前优先级最高的线程,进入就绪状态 // a.notifyAll();//唤醒当前所有的线程,进入就绪状态 } } } } class User implements Runnable{ Acount acount; int money; public User(Acount acount,int money){ this.acount = acount; this.money = money; } public void run() { acount.drawing5(money,acount); } }
打印结果:

四、经典例题:生产者/消费者问题
生产者(Productor)将产品交给店员(Cleak),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,等店中有产品了再通知消费者来取走产品。
这里可能出现两个问题:
1.生产者比消费者块时,消费者会漏掉一些数据没有取到。
2.消费者比生产者快时,消费者会取走相同的数据。
package day20; /** * 生产者和消费者 * */ public class Test3 { public static void main(String[] args){ final Clerk c = new Clerk(); //消费时不生产,生产时不消费 //生产者 new Thread(new Runnable(){ public void run() { // TODO Auto-generated method stub synchronized (c) { while(true){//无限循环代表无限的生产次数 if(c.productNum == 0){//产品数为0,开始生产 System.out.println("产品数为0,开始生产"); while(c.productNum < 4){ c.productNum++;//增加产品 System.out.println("库存:" + c.productNum); } System.out.println("产品数为:" + c.productNum + ",结束生产"); c.notify();//唤醒消费者 }else{ try { c.wait();//让生产者线程等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } },"生产者").start(); //消费者 new Thread(new Runnable(){ public void run() { // TODO Auto-generated method stub synchronized (c) { while(true){//无限循环代表无限的消费次数 if(c.productNum == 4){//产品数为4,开始消费 System.out.println("产品数为4,开始消费"); while(c.productNum > 0){ c.productNum--;//消费产品 System.out.println("库存:" + c.productNum); } System.out.println("产品数为:" + c.productNum + ",结束消费"); c.notify();//唤醒生产者线程 }else{ try { c.wait();//让消费者者线程等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } },"消费者").start(); } } class Clerk{ public static int productNum = 0; }
部分打印结果:


浙公网安备 33010602011771号