wait和notify是Java最基本的线程间通讯机制,体现了线程的交互,用于信息的传递。例如在生产者消费者模式中,利用阻塞和唤醒使不一样线程之间配合实现业务逻辑。java
阻塞阶段--wait,调用对象的wait方法,线程进入WAITING状态,阻塞挂起,释放锁。
wait阻塞后,直到下面状况之一发生时,线程才会被唤醒。ide
唤醒阶段 --notify/notifyAll测试
synchronized(this) { while(条件){ wait(); } }
synchronized (resourceA) { synchronized (resourceB) { try { resourceA.wait(); // 只释放resourceA锁 } catch (InterruptedException e) { e.printStackTrace(); } } }
注意点:调用某个对象的notify,只能唤醒与该对象对应的线程。调用wait也只释放当前的那把锁。this
EntrySet:入口集;WaitSet:等待集;The owner:线程拥有锁。’
锁的运行原理:开始线程在入口集和等待集竞争锁【1】,此时线程A获取到了锁【2】,入口集和等待集中的线程进入BLOCKED。此时A能够正常运行完释放锁【6】,也能够调用wait释放锁进入等待集【3】。等待集线程被唤醒【4】后,进入另外一个等待集,与入口集的线程一块儿竞争锁【5】。线程
生产者消费者模式能够解耦生产者和消费者,使二者更好地配合。
设计
// 生产和消费100个产品 public class ProducerConsumerModelByWaitAndNotify { public static void main(String[] args) { // 建立仓库 Storage storage = new Storage(); // 建立生产者消费者线程 Thread producer = new Thread(new ProducerTask(storage)); Thread consumer = new Thread(new ConsumerTask(storage)); producer.start(); consumer.start(); } } class ProducerTask implements Runnable { private Storage storage; public ProducerTask(Storage storage) { this.storage = storage; } @Override public void run() { // 生产100个产品 for (int i = 0; i < 100; i++) { storage.put(); } } } class ConsumerTask implements Runnable { private Storage storage; public ConsumerTask(Storage storage) { this.storage = storage; } @Override public void run() { for (int i = 0; i < 100; i++) { storage.take(); } } } class Storage { private int maxSize; private Queue<Date> storage; public Storage() { this.maxSize = 10; // 队列最大是10 this.storage = new LinkedList<>(); } /** * wait和notify须要首先获取到锁,所以须要使用synchronized方法或者同步代码块 */ public synchronized void put() { // 仓库已满,没法生产更多产品,让出锁 while (storage.size() == maxSize) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } storage.add(new Date()); System.out.println("生产者生产产品,此时仓库产品数:" + storage.size()); // 通知消费者消费 notify(); } public synchronized void take() { // 仓库为空,没法获取到产品,线程让出锁 while (storage.size() == 0) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } storage.poll(); System.out.println("消费者消费产品,此时仓库产品数:" + storage.size()); // 通知生产者生产 notify(); } }
主要是为了让通讯更加可靠,防止死锁、永久等待的发生。code
wait放到synchronized代码中对线程有必定的保护做用。假设没有synchronized的保护,线程A在运行到wait语句以前,切换到线程B执行了notify语句,此时执行了wait语句释放锁后,没有线程唤醒,致使了永久等待。对象
sleep方法是针对单个线程的,与其余线程无关,无需放入到同步代码块中。blog
wait和notify是锁级别操做,而锁是属于某个对象的,锁标识在对象的对象头中。若是将wait和notify定义在线程中,则会有很大的局限性。例如每一个线程均可能会休眠。若是某个线程持有多个锁,并且锁之间是相互配合的时,wait方法在Thread类中,就没有办法实现线程的配合。队列
我的理解: 调用线程对象的wait方法,也就是说以线程为锁。wait和notify的初衷就是用来线程间通讯,若是以线程为锁,不利于设计流程。