看到一道面试题,写一个多线程程序,交替输出1、2、1、2……
先写下程序:
/** * Created by Andrew on 2015/10/28. */ public class OutputThread implements Runnable { private int num; private Object lock; public OutputThread(int num,Object obj){ this.num = num; this.lock = obj; } @Override public void run() { try{ while(true) { synchronized (lock){ lock.notifyAll(); lock.wait(); System.out.println(num); } }}catch (Exception e){ e.printStackTrace(); } } public static void main(String[] args) { final Object obj = new Object(); Thread thread1 = new Thread(new OutputThread(0,obj)); Thread thread2 = new Thread(new OutputThread(1,obj)); thread1.start(); thread2.start(); } }
然后用JDK1.8文档来解释下这两个方法:
<a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#wait--">wait</a>()
Causes the current thread to wait until another thread invokes the notify()
method or the notifyAll()
method for this object.
The current thread must own this object's monitor.
This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Thread T becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:
Throws:
IllegalMonitorStateException - if the current thread is not the owner of the object's monitor.
InterruptedException - if any thread interrupted the current thread before or while the current thread was waiting for a notification. The interrupted status of the current thread is cleared when this exception is thrown.
<span><a href="http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notifyAll--">notifyAll</a>()</span>
Wakes up all threads that are waiting on this object's monitor.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
Throws:IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.
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.
Throws:IllegalMonitorStateException - if the current thread is not the owner of this object's monitor.
首先,调用wait()的前提是,当前线程A拥有该对象的锁,否则调用wait()时会抛出IllegalMonitorStateException 。wait() 会使得当前线程A进入该对象的等待列表,并释放锁,直到发生下面的任何事情之一:
调用notifyAll()则会使得所有等待该对象锁的线程被唤醒,去竞争这个对象锁。与notify()的区别是,前者会唤醒所有等待该对象锁的线程,后者则把选择权交给JVM。
然后解释下这个程序为什么可以交替输出1、2、1、2……而不会混乱。
假设线程A先进入同步代码块儿
while(true) { synchronized (lock){ lock.notifyAll(); lock.wait(); System.out.println(num); } }
……
流程就是这么个流程,通过这个小例子对wait()、notify()和notifyAll()进行理解吧。