notify()与wait()
先来说一下notify()、notifyAll()与wait()方法.
可能会令初学者可能比较困惑的是,作为线程通讯的方式,notify()、notifyAll()与wait()却被定义在Object类上。其实很好理解,wait()的本质是释放已获取的锁对象并阻塞等待被唤醒,而notify()则是释放已获取的锁对象并唤醒在wait()中等待同一个锁的线程。因此调用方式便是
[锁对象].wait()
或者
[锁对象].notify().
若不指明调用对象,实际上就用this关键字代替了[锁对象],即当前对象本身作为锁对象。
若调用上述代码时并未获取任何锁,或者指定的锁对象和获取的锁不符,都会抛出 java.lang.IllegalMonitorStateException 生产者者与消费者
生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据。
需要如下三部分组成:
1.存储对象:即图中的Shared Buffer。存储对象中防止生产者的产品,同时让消费者消费。
2.生产者,负责生产商品并添加至存储对象。当存储放满时停止生产。当生产完一个产品时,通知消费者消费。 注意,这里容易产生一个误解:通知消费者消费,并不代表消费者一定会去消费。有可能还未进入消费的代码块时,CPU又可能由于分时的工作原理,放下消费者转而继续执行生产者。又或者可能有多个生产者同时生产。
3.消费者,负责消费商品。当存储对象中商品为空时等待。
实现方式,根据线程通讯操作所处位置,可分为如下两种:
(一) 在消费者和生产者中完成线程通讯
public class Repository { //仓储类 private LinkedList<Object> repository = new LinkedList<Object>(); //仓储实现 private int MAX = 10; //最大商品数量 private int count=0; //当前商品数量 public boolean add(Object product){ count++; return this.repository.add(product); } public Object remove(){ count--; return this.repository.removeLast(); } public int getMAX() { return MAX; } public int getCount() { return count; } }
public class Producer implements Runnable{ private Repository repository; public Repository getRepository() { return repository; } public void setRepository(Repository repository) { this.repository = repository; } public Producer(Repository repository){ this.repository=repository; } @Override public void run() { while (true) { synchronized (repository) { try { while (repository.getCount()==repository.getMAX()) { //当商品数量已满时,暂停生产 System.out.println("respositry is full , please wait"); repository.wait(); } Object newOb = new Object(); if (repository.add(newOb)) { //生成商品,并唤醒所有该锁的等待者 System.out.println("Producer put a Object to respositry"); Thread.sleep((long) (Math.random() * 3000)); repository.notifyAll(); } } catch (InterruptedException ie) { System.out.println("producer is interrupted!"); } } } }
public class Consumer implements Runnable{ public Repository respository; public Repository getRespository() { return respository; } public void setRespository(Repository respository) { this.respository = respository; } public Consumer(Repository repository){ this.respository=repository; } @Override public void run() { while (true) { synchronized (respository) { try { while (respository.getCount() == 0) { //当商品为空时,暂停消费 System.out.println("repositry is empty , please wait"); respository.wait(); } respository.remove(); //消费商品 System.out.println("Comsumer get a Object from repositry"); Thread.sleep((long) (Math.random() * 3000)); respository.notifyAll(); } catch (InterruptedException ie) { System.out.println("Consumer is interrupted"); } } } } }
public class Client { public static void main(String[] args) { Repository repository=new Repository(); new Thread(new Producer(repository)).start(); new Thread(new Consumer(repository)).start(); } }