本文共 2648 字,大约阅读时间需要 8 分钟。
在多线程开发中,为避免共享资源数据错误,常使用互斥(synchronized)机制实现多线程对共享资源的访问同步。然而,当线程间需要相互提供支持的情况下,仅有互斥机制是不够的,这就是线程协作机制起作用的时候了。
线程协作是多线程互斥同步的基础上,使线程之间依照一定条件,有目的、有计划地交互协同工作,这是一种较高级的线程同步方式。
Java提供了一个精心设计的线程间通信机制即wait-notify机制,通过该机制可以实现线程协作。
wait-notify机制是通过使用wait()、notify()和notifyAll()三个方法来实现的。
这三个方法均定义在Object类中,是final修饰的实例方法。
这三个方法必须在synchronized代码中调用,而且只有通过锁对象才能调用这三个方法。
wait()方法
通过当前同步锁调用该方法的线程在当前同步锁下进入等待状态,直到其他线程通过相同的同步锁调用notify( )或者notifyAll()方法。notify( )
通过当前同步锁调用该方法,唤醒在当前同步锁下等待的线程中的一个结束等待。notifyAll()
通过当前同步锁调用该方法,唤醒在当前同步锁下等待的所有线程结束等待。在多线程程序设计中,生产者和消费者问题是典型的需要线程协作的场景。这类问题一般存在两类线程和一个共享数据资源,一类是提供共享数据的线程即生产者,另一类消耗共享数据的线程即消费者。这类问题具有以下特点:
面包店的柜橱用来存放面包,面包师傅负责将烤好面包放到柜橱中,店面伙计负责将柜橱中的面包售出。存在以下两种问题:
解决问题的办法
//面包柜public class Cupboard { private int count;//面包数量 private int size;//面包容量 public Cupboard(int size ){ this.size=size; } //放入一个面包,该方法是同步方法,同步锁为this public synchronized void add(){ while(this.isFull()) { System.out.println(Thread.currentThread().getName()+":柜内面包数:"+count+",已满!等待中......"); try { this.wait();//在当前同步锁对象(this)下等待 } catch (InterruptedException e) { e.printStackTrace(); } } count++; System.out.println(Thread.currentThread().getName()+":放入一个面包,柜内面包数:"+count); this.notifyAll();//唤醒在当前同步锁对象(this)下等待的所有线程 Thread.yield();//让步,给其它线程以运行机会 } //取出一个面包,该方法是同步方法,同步锁为this public synchronized void remove(){ while(this.isEmpty()) { System.out.println(Thread.currentThread().getName()+":柜内面包数:"+count+",已空!等待中......"); try { this.wait();//在当前同步锁对象(this)下等待 } catch (InterruptedException e) { e.printStackTrace(); } } count--; System.out.println(Thread.currentThread().getName()+":取出一个面包,柜内面包数:"+count); this.notifyAll();//唤醒在当前同步锁对象(this)下等待的所有线程 Thread.yield();//让步,给其它线程以运行机会 } //面包柜是否为空 public boolean isEmpty(){ return count<1; } //面包柜是否已满 public boolean isFull(){ return count>=size; }}
public class Test { public static void main(String[] args) { final Cupboard cupboard = new Cupboard(5);//创建面包柜,容量为5个面包 //创建三个面包师线程和三个伙计线程,并启动。每个面包师烤一百个面包,每个伙计销售一百个面包。 for(int i=1;i<=3;i++) { //面包师线程 new Thread("面包师"+i) { public void run() { for(int i=0;i<100;i++) { cupboard.add(); } } }.start(); //伙计线程 new Thread("伙计"+i) { public void run() { for(int i=0;i<100;i++) { cupboard.remove(); } } }.start(); } }}
运行结果截图如下:
转载地址:http://uihdi.baihongyu.com/