内置锁 与 wait notify 机制
每个Java对象都有一个内置锁,通过 synchronized
关键字使用。线程之间可以通过 Object 类的 wait, notify, notifyAll
进行协调。
wait, notify, notifyAll
方法说明:
wait
:在其他线程调用此对象的notify()
方法或notifyAll()
方法前,导致当前线程等待。当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用notify
方法,或notifyAll
方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。notify
:唤醒在此对象监视器上等待的单个线程,直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意性的,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。notifyAll
:唤醒在此对象监视器上等待的所有线程,直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。
以一个有界缓存为例,展示了内置锁和 wait、notify、notifyAll
的一般用法:
public class BoundedBuffer<T> {
private final Object[] buffer;
private final int length;
public BoundedBuffer(int length ) {
if (length < 0) {
throw new IllegalArgumentException("length < 0");
}
this.length = length ;
buffer = new Object[length ];
}
// synchronized 用于方法上,表示一个同步方法,线程进入方法前自动获得内置锁
public synchronized void put(T obj) throws InterruptedException {
// 线程被唤醒时,条件不一定满足(虚假唤醒),所以需要在循环里进行测试、等待
while (isFull()) {
// 在当前的对象实例上等待,由其他线程调用 notifyAll 或 notify 方法唤醒
wait();
}
doPut(obj);
// 唤醒在此对象监视器上等待(通过wait方法进入等待)的所有线程。
// 直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。
notifyAll();
}
public synchronized T take() throws InterruptedException {
T object = null;
while (isEmpty()) {
wait();
}
object = doTake();
notifyAll();
return object;
}
private void doPut(T obj) { // not implemented
}
private T doTake() { // not implemented
return null ;
}
private boolean isEmpty() { // not implemented
return false ;
}
private boolean isFull() { // not implemented
return false ;
}
}