wait-notify必须配合synchronized,并且为重量级锁。
await-signal必须配合lock
目录
wait()和wait(long timeoutMillis)
图解monitor原理
在Java中,每个对象都有一个内置的锁,也称为监视器锁(monitor)。当一个线程试图进入一个同步块(synchronized block)时,它需要首先获取该对象的监视器锁。如果锁已经被其他线程持有,那么试图获取锁的线程将被阻塞,直到锁被释放。
在monitor中有一个owner和两个队列。其中owner指的是当前拥有锁的线程,而两个队列分别为:
1、同步队列:用于存放等待获取对象锁的线程。当对象的锁被释放时,同步队列中的线程会被唤醒并尝试获取锁。
2、等待队列:用于存放调用了对象的wait()方法的线程。当其他线程调用了对象的notify()或notifyAll()方法时,等待队列中的线程会被唤醒并移动到同步队列中,等待获取对象的锁。
wait()和wait(long timeoutMillis)
在Java中,wait()方法是Object类的一个方法,用于让当前线程进入等待状态。wait()方法也会让当前线程释放它所持有的该对象的锁,以使其他线程可以获取该锁并执行同步代码块。
在Object类中,有两个关于wait的方法:一个是wait() ,另一个是wait(long timeoutMillis)。而wait()方法实际上就是调用了wait(0):
public final void wait() throws InterruptedException {
wait(0L);
}
wait(long timeoutMillis)方法,它会让当前线程等待指定的时间(以毫秒为单位)。如果在这段时间内,其他线程调用了同一对象的notify()或notifyAll()方法,那么当前线程会被唤醒并尝试重新获取锁。如果在这段时间内没有其他线程调用这些方法,那么当前线程会在等待时间结束后自动被唤醒。需要注意的是,即使等待时间结束,也并不意味着当前线程可以立即获取锁并继续执行。如果有其他线程正在持有锁,那么当前线程仍然需要等待锁被释放。
notify() 和notifyAll()
在Java中,notify()和notifyAll()是Object类的两个方法,用于唤醒在该对象上等待的线程。这两个方法必须在同步块或同步方法中调用,也就是当前线程必须持有该对象的锁。
notify()方法:会随机唤醒在该对象上等待的一个线程。如果有多个线程在等待,它只会选择其中一个线程并将其唤醒。
notifyAll()方法:会唤醒在该对象上等待的所有线程。所有被唤醒的线程将会竞争重新获取锁,然后继续执行。
public class MyRunnable implements Runnable {
private Object lock = new Object();
public void doNotify() {
synchronized (lock) {
lock.notify(); //唤醒等待队列中的一个线程
}
}
public void doNotifyAll() {
synchronized (lock) {
lock.notifyAll();//唤醒等待队列中的所有线程
}
}
@Override
public void run() {
synchronized (lock) {
try {
lock.wait(); //当前线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
// 当前线程被唤醒后会继续从这里执行
}
}
}
wait()和sleep()
在Java中,wait()和sleep()都可以让当前线程暂停执行,但它们的用途和行为有一些重要的区别: 1. 来源不同:wait()是Object类的方法,而sleep()是Thread类的静态方法。
2. 锁的释放:当线程执行wait()方法时,它会释放它所持有的该对象的锁,这使得其他线程可以获取该锁并执行同步代码块。而当线程执行sleep()方法时,它不会释放任何锁。
3. 唤醒方式:wait()方法可以通过notify()或notifyAll()方法来唤醒等待的线程。而sleep()方法则在指定的时间过后自动唤醒,或者可以通过interrupt()方法来中断线程的睡眠。
4. 使用场景:wait()、notify()和notifyAll()方法通常用于多个线程间的协调和通信,比如生产者/消费者模型。而sleep()方法通常用于让当前线程暂停一段时间,比如模拟耗时操作或者控制线程的执行速度。