简介
1.wait方法用于让线程等待一个条件,当条件满足的时候才开始执行
如 消费者执行的条件是队列非空,所以消费者线程需要等到非空 才能执行
特点
- wait()方法释放锁。
- wait()是Object类的方法。
- wait()是非静态方法 - public final void wait() throws InterruptedException {// …}
- 需要通过notify()或notifyAll()方法通知wait()。
- 需要从循环中调用wait()方法以处理误唤醒。
- 必须从synchronized上下文(即synchronized方法或块)调用wait()方法,否则会抛出IllegalMonitorStateException.
wait与sleep区别
synchronized(LOCK) {
Thread.sleep(1000); // 不释放LOCK的内置锁
}
synchronized(LOCK) {
LOCK.wait(); // 释放LOCK锁
}
通用使用模板
/**
* wait通用使用模式
* @param action
*/
private void waitDemo(Runnable action) {
synchronized (lock) {// 获取锁
try {
while(!condition) {
lock.wait();
}
// 条件满足之后开始执行任务
action.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.notify方法 用于唤醒 等待在同一个对象上的线程
如生产者线程,在生产完后 调用该方法,可以唤醒等待队列非空的消费者线程。
private void notifyDemo(Runnable action) {
synchronized (lock) {// 获取锁
action.run();
lock.notifyAll();
}
}
3.the owner线程在wait的时候会释放monitor锁,并进入Wait Set
4.其它线程从Entry Set 获取锁后成为monitor新Owner,执行任务后,notifyAll()会唤醒Wait Set中的所有线程
5.醒来的wait线程 重新获取acquire锁,成为Owner,然后重新检查condition,如果不符合条件,继续等待,如果符合,执行后续任务,退出同步块释放锁 退出!
例子-生产者-消费者
package concurrency;
import java.util.LinkedList;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class WaitNotifyExample {
//仓库最大容量
private static final int MAX_SIZE = 10;
//仓库存储的载体
private static LinkedList list = new LinkedList();
//生产产品
public static void produce(int num){
//同步
synchronized (list){
//仓库剩余的容量不足以存放即将要生产的数量,暂停生产
while(list.size()+num > MAX_SIZE){
System.out.println(Thread.currentThread().getName() + ":需要生产:" + num + "\t【库存量】:"
+ list.size() + "\t暂时不能执行生产任务!");
try {
//条件不满足,生产阻塞
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=0;i<num;i++){
list.add(new Object());
}
System.out.println(Thread.currentThread().getName() + ": 生产" + num + "\t【现仓储量为】:" + list.size());
list.notifyAll();
}
}
//消费产品
public static void consume(int num){
synchronized (list){
//不满足消费条件,仓库库存不够
while(num > list.size()){
System.out.println(Thread.currentThread().getName() + ": 将消费:" + num + "\t【库存量】:"
+ list.size() + "\t暂时不能执行消费任务!");
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 条件满足,开始消费
for(int i=0;i<num;i++){
list.remove();
}
System.out.println(Thread.currentThread().getName() + ": 消费" + num + "\t【现仓储量为】:" + list.size());
// 消费过之后需要通知 所有等待在list对象上的线程
list.notifyAll();
}
}
public static void main(String[] args) {
int proNum = 2;
int conNum = 3;
Executor executor = Executors.newFixedThreadPool(proNum + conNum);
for(int i=0;i<conNum;i++) {
executor.execute(new Runnable() {
@Override
public void run() {
consume(1);
}
});
}
for (int i=0;i<proNum;i++) {
executor.execute(new Runnable() {
@Override
public void run() {
produce(1);
}
});
}
}
}