wait-notify机制
a. 当synchronized方法中的wait方法被调用时,当前线程将被中断运行,并且放弃该对象的锁
b. 一旦线程调用了wait方法,它便进入该对象的等待列表。要从等待列表中删除该线程,使它有机会继续运行,其它线程必须调用同一个对象上的notify或者notifyAll方法
c. 当线程再次成为可运行的线程后,它们便试图重新进入该对象。一旦可以使用该对象锁时,其中的一个线程将锁定该对象,并且从它上次调用wait方法后的位置开始继续运行
实例:
package com.bijian.thread;
public class MyThread extends Thread {
private Object o;
MyThread(Object o) {
this.o = o;
}
public void run() {
synchronized (o) {
try {
System.out.println(getName() + " before wait");
o.wait();
System.out.println(getName() + " after wait");
} catch (InterruptedException e) {
}
}
}
}
package com.bijian.thread;
public class WaitNotifyAllDemo {
public static void main(String[] args) {
Object lock = new Object();
MyThread mt1 = new MyThread(lock);
mt1.setName("A");
MyThread mt2 = new MyThread(lock);
mt2.setName("B");
MyThread mt3 = new MyThread(lock);
mt3.setName("C");
mt1.start();
mt2.start();
mt3.start();
System.out.println("main thread sleeping");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("main thread awake");
synchronized (lock) {
lock.notifyAll();
}
}
}
运行结果:
A before wait main thread sleeping B before wait C before wait main thread awake C after wait B after wait A after wait
实例分析:主线程在打印出“ main thread awake ”之前, A 、 B 、 C 线程应该都已运行至 wait 方法,即 A 、 B 、 C 线程都在 wait 通知队列,当主线程运行完 lock.notifyAll(); 语句后, A 、 B 、 C 线程对象都会从 wait 队列转入 lock 队列,接下来, A 、 B 、 C 线程对象平等竞争锁资源,随机从 lock 队列中取出执行。
小结:
a. 如果两个或多个线程修改一个对象,请将执行修改的方法声明为synchronized方法。受到对象修改影响的只读方法也必须实现同步。
b. 如果一个线程必须等待某个对象的状态出现变更,那么它应该在对象的内部等待而不是在外面等待。这可以通过进入一个synchronized方法,并且调用wait方法来实现。
c. 不要在synchronized方法中花费大量的时间。大多数操作只是更新数据,然后很快返回。
d. 每当一个方法改变某个对象的状态时,它就应该调用notifyAll方法。这样可以给等待线程一个机会,以便查看环境有没有发生变化。
e. 记住,wait和notifyAll/notify方法都属于Object类的方法,而不是Thread类的方法。反复检查你对wait方法的调用与同一对象上的通知是否匹配。