java中,每个对象都拥有一个监视器,也就是锁。监视器(monitor)乍一听比较抽象,举个例子来说,它有点像一个厕所,假设厕所一次只能容下一个人,那么这个厕所就可以说是监视器了,监视器(厕所)监视着上厕所的每一个人,每次只允许一个人进入厕所,进入之后则会把厕所锁上,防止其它人再进入,其它人要想进入厕所则必须等待上一个人上完厕所才能进入。wait()方法的作用是:在拥有某个对象(暂时称之为lock)的锁(也就是监视器)的情况下,调用lock.wait()方法的线程当会等待,直到另外的某个线程再次调用lock.notify()或lock.notifyAll()。另外lock.notify()也并不总是可靠的,假如当前监视器上等待的线程不止一个,则另外某个线程调用一次lock.notify()方法时,只会唤醒一个调用了lock.wait()的线程。
下面我们来看一个例子,第一个是Thread1:
package com.test.thread; public class Thread1 extends Thread { private final Object lock; public Thread1(Object lock){ this.lock = lock; this.setName("thead1"); } @Override public void run() { synchronized (lock) { try { System.out.println(getName() + " start."); lock.wait(); System.out.println(getName() + " end."); } catch (InterruptedException e) { e.printStackTrace(); } } } }
接下来是Thread2:
package com.test.thread; public class Thread2 extends Thread { private final Object lock; public Thread2(Object lock){ this.lock = lock; this.setName("thead2"); } @Override public void run() { synchronized (lock) { try { System.out.println(getName() + " start."); Thread.sleep(100); lock.notify(); System.out.println(getName() + " end."); } catch (Exception e) { e.printStackTrace(); } } } }
main方法:
/** * @param args */ public static void main(String[] args) { Object o = new Object(); //Object o2 = new Object(); Thread1 t1 = new Thread1(o); Thread2 t2 = new Thread2(o); t1.start(); t2.start(); }
执行上面的程序输出:
thead1 start.
thead2 start.
thead2 end.
thead1 end.
首先启动两个线程,执行thead1时获得对象lock上的监视器(也就是锁),然后在thead1上调用了lock.wait(),它导致thread1线程处于等待状态,同时它也会释放lock上面的锁;接着thead2开始执行,它获得thread1释放的锁,然后调用lock.notify(),这会唤醒一个在此监视器上等待的一个线程,这时只有一个线程在等待,那就是thread1,这时thread1又恢复到可运行状态,它会和thread2一起竞争CPU资源,也就是说后面两句的输出顺序是不确定的,取决于谁获得CPU的执行时间。
假如我们使用的对象不是同一个会怎么样呢?我们将main方法代码更改一下:
1 /** 2 * @param args 3 */ 4 public static void main(String[] args) { 5 Object o = new Object(); 6 Object o2 = new Object(); 7 Thread1 t1 = new Thread1(o); 8 Thread2 t2 = new Thread2(o2); 9 t1.start(); 10 t2.start(); 11 }
这时只输出了:
thead1 start.
thead2 start.
thead2 end.
。
thread2一直处于等待状态,这是因为我们的两个线程同步时使用的不是同一个锁,thread2使用的o2,调用o2.notify()并不会唤醒thread1,因为thread1在o上面等待。