Multi-Programming-7 wait() and notify()

来源:互联网 发布:安慕希网络促销方案 编辑:程序博客网 时间:2024/05/19 18:10

1. 什么是wait() & notify()? What is wait() and notify()?

这里有关于wait() & notify()以及 ReentrantLock, await(), signal()的问答
wait()和notify(): 这是Java语言提供的一种机制,使得一个线程在某种条件满足之前处于阻塞状态,直到条件满足后才能继续运行。
wait:使得当前线程释放对象的锁,直到其它线程唤醒该线程,或被中断。
notify:唤醒等待在该对象上的线程。被唤醒线程只有在获取该对象锁之后才能继续运行。

  • wait()方法

官方解释:
void java.lang.Object.wait() throws InterruptedException

    Causes the current thread to wait until another thread invokes the java.lang.Object.notify() method or the java.lang.Object.notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.中文翻译:    当前线程必须拥有对象的monitor,调用wait()方法时,当前线程释放该对象的monitor, 直到其他线程唤醒等待在该对象的monitor的线程,一般使用notify()或notifyAll()方法。其中notify()唤醒一个等待在该对象monitor的线程,notifyAll()唤醒所有等待在该对象monitor的线程。
  • notify()方法

        void java.lang.Object.notify()    Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.    The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. 

    中文翻译:
    唤醒一个等待在该对象monitor上的一个线程,被唤醒的线程在当前线程重新释放掉在该对象上锁后才能继续执行

2. 使用notify() & wait()实现的BlockingQueue实例

这里注意2点:wait() & notify() 方法必须在同步代码块中被调用,否则会出现 missed signal遗失信号量问题”;必须把判断条件放在while循环中,因为可能在notify没有被调用的情况下出现spurious wakeup伪唤醒
1. Missed signal: 比如假设没有同步,线程1在put时,发现队列已满,在线程1还未被阻塞时,线程2进行了take操作,然后唤醒等待的线程1。然而,线程1此时将执行wait操作,使得此次唤醒无效。
2. Spurious notify: 等待线程有时可能会在notify方法没有调用时被激活,放在while循环中将持续检验,直到满足条件。

package com.fqyuan._5wait;import java.util.LinkedList;import java.util.Queue;public class BlockingQueueWithWait<T> {    private int capacity;    private Queue<T> queue = new LinkedList<T>();    public BlockingQueueWithWait(int capacity) {        this.capacity = capacity;    }    public synchronized void put(T item) throws InterruptedException {        while (queue.size() == capacity)            wait();        queue.add(item);        notify();    }    public synchronized T take() throws InterruptedException {        while (queue.isEmpty())            wait();        T item = queue.remove();        notify();        return item;    }}

3. 高级同步机制实现的await&signal

package com.fqyuan._5wait;import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class BlockingQueueWithHigh<T> {    private int capacity;    private Queue<T> queue = new LinkedList<>();    private ReentrantLock lock = new ReentrantLock();    private Condition notFull = lock.newCondition();    private Condition notEmpty = lock.newCondition();    public BlockingQueueWithHigh(int capacity) {        this.capacity = capacity;    }    public void put(T item) throws InterruptedException {        try {            lock.lock();            while (queue.size() == capacity)                notFull.await(); // Cause current thread to wait until it is                                    // signaled or interrupted.            queue.add(item);            notEmpty.signal();        } finally {            lock.unlock();        }    }    public T take() throws InterruptedException {        try {            lock.lock();            while (queue.isEmpty())                notEmpty.await();            T item = queue.remove();            notFull.signal();            return item;        } finally {            lock.unlock();        }    }}

4. 可运行实例

注意:这里waiPizzyGuy()方法中如果不掉用notify() 方法,则该线程不会释放对象锁,所以另一个线程将会一直等待下去。

package com.fqyuan._5wait;public class SimpleDemo {    public static void main(String[] args) {        PizzaEating p = new PizzaEating();        Thread t1 = new Thread(new Runnable() {            @Override            public void run() {                try {                    p.eatPizza();                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        });        Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                p.waitPizzaGuy();            }        });        t1.start();        t2.start();        try {            t1.join();            t2.join();        } catch (Exception e) {            // TODO: handle exception        }    }}class PizzaEating {    private boolean isArrived = false;    public synchronized void eatPizza() throws InterruptedException {        while (!isArrived)            this.wait();        System.out.println("Pizza yummy!");    }    public synchronized void waitPizzaGuy() {        try {            System.out.println("Waiting for pizza guy!");            Thread.sleep(2000);            this.notify();            isArrived = true;            System.out.println("Pizza guy arrived.");        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }}
//Running result:Waiting for pizza guy!Pizza guy arrived.Pizza yummy!

You may get related notes and code here.