前提 - wait()为什么在Object中
- Java中每一个对象都可以成为一个监视器
(Monitor)
, 该Monitor由一个锁(lock)
, 一个等待队列(waiting queue)
, 一个入口队列(entry queue)
组成。 - 对于一个对象的方法, 如果没有synchronized关键字修饰, 该方法可以被任意数量的线程,在任意时刻调用。
对于添加了synchronized关键字的方法,任意时刻只能被唯一的一个获得了对象实例锁的线程调用。 - synchronized用于实现多线程的同步操作
所以获取到对象锁的线程才能执行wait()方法。
Object.wait() 使用
这个方法导致当前线程等待,直到其他的线程调用这个对象的Object.notify方法或者Object.notifyAll()方法。
当前线程必有拥有这个对象的监视器(获得锁).并且当前线程把自己放到Object对象的等待列队中,并释放Object的所有的同步声明。
wait() Object.notify
一个线程修改了一个值之后另一个线程感知到线程的变化。我们可以通过wait()来阻塞一个线程,然后通过业务条件来进行切换从而实现生产者消费者模型。
调用Object.wait() Object.notify 为什么加锁呢?
public static Object lock = new Object();
public static boolean flag = true;
public static void main(String[] args) {
//Thread1
new Thread(() -> {
try {
//1
if (flag) {
//4
lock.wait();
}
TimeUnit.SECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "thread1").run();
//Thread2
new Thread(() -> {
System.out.println("释放");
//2
flag = false;
//3
lock.notify();
}, "thread2").run();
}
如果不加锁的话,在多线程环境按照1234步骤执行,会造成先Thread2.notify()而 Thread1.wait()线程一直处于等待状态无法释放。
原理
wait()
, notify()
, notifyAll()
和 synchronized
需要搭配使用, 用于线程同步wait()
总是在一个循环中被调用,挂起当前线程来等待一个条件的成立。 Wait调用会一直等到其他线程调用notifyAll()
时才返回。当一个线程在执行synchronized
的方法内部,调用了wait()
后, 该线程会释放该对象的锁, 然后该线程会被添加到该对象的等待队列中(waiting queue)
, 只要该线程在等待队列中, 就会一直处于阻塞状态,不会被调度执行。 要注意wait()
方法会强迫线程先进行释放锁操作,所以在调用wait()
时, 该线程必须已经获得锁,否则会抛出异常。但是由于wait()
在synchronized
的方法内部被执行, 锁一定已经获得, 就不会抛出异常了。
当一个线程调用一个对象的notify()
方法时, 调度器会从所有处于该对象等待队列(waiting queue)
的线程中取出任意一个线程, 将其添加到入口队列(entry queue)
中. 然后在入口队列中的多个线程就会竞争对象的锁, 得到锁的线程就可以继续执行。 如果等待队列中(waiting queue)
没有线程, notify()
方法不会产生任何作用.notifyAll()和
notify()工作机制一样, 区别在于
notifyAll()会将等待队列
(waiting queue)中所有的线程都添加到入口队列中
(entry queue).otifyAll()
比notify()
更加常用, 因为notify()
方法只会唤起一个线程,且无法指定唤醒哪一个线程.
网友评论