“等待-通知”是挺有用的一个编程范式、设计模式或者说套路。白话讲就是一个线程执行需要等待一个事件发生或者说一个条件具备,然后另一个线程去触发这个事件或者更新这个条件,那么前者就可以触发执行了。这种设计可以解藕两个线程的业务逻辑,类似于生产者和消费者。
实现这个模式,主要有3种方法:线程自旋不断的去轮询条件是否具备、Object监视器方法wait()/notify() 、Condition接口
1、比较容易想到的“经典的方法”
一个线程不断的自旋,去查询自己能够继续执行的条件,一旦发现条件具备(另一个线程修改了条件),则结束自旋,去执行业务逻辑。
packagecom.wangan.concurrent;importjava.util.concurrent.TimeUnit;public classWaitAndNotifyPattern {public static volatile boolean flag = false;public static voidmain(String[] args) {new Thread(newWait()).start();try{
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e) {
e.printStackTrace();
}new Thread(newNotify()).start();try{
TimeUnit.SECONDS.sleep(5);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}class Wait implementsRunnable{
@Overridepublic voidrun() {while(!WaitAndNotifyPattern.flag) {try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("条件还未满足,睡1秒");
}
System.out.println("wait条件满足了,执行业务逻辑");
}
}class Notify implementsRunnable{
@Overridepublic voidrun() {
WaitAndNotifyPattern.flag= true;
System.out.println("notify修改了条件为true");
}
}
输出:
条件还未满足,睡1秒
条件还未满足,睡1秒
条件还未满足,睡1秒
条件还未满足,睡1秒
notify修改了条件为true
条件还未满足,睡1秒 这里体现了发现条件不及时
wait条件满足了,执行业务逻辑
这个方法最大的缺陷在于需要线程sleep,休眠多少时间是一对儿矛盾,少了的话cpu受不了,多了的话条件变了这边发现不及时。
所以就有了下面两个新方法。
2、使用Object监视器方法配合synchronized实现等待通知机制
packagecom.wangan.basic;importjava.util.concurrent.TimeUnit;public classWaitAndNotify {public static Object lock = newObject();public static boolean flag = false;public static voidmain(String[] args) {new Thread(newWait()).start();
sleepSecond(5);new Thread(newNotify()).start();
}public static void sleepSecond(intsec) {try{
TimeUnit.SECONDS.sleep(sec);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}class Wait implementsRunnable{
@Overridepublic voidrun() {synchronized(WaitAndNotify.lock) {while(!WaitAndNotify.flag) {try{
System.out.println("Wait还未具备条件,等待");
WaitAndNotify.lock.wait();//等待并释放锁
} catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Wait获得了条件,执行业务逻辑");
}
}
}class Notify implementsRunnable{
@Overridepublic voidrun() {synchronized(WaitAndNotify.lock) {
WaitAndNotify.flag= true;
WaitAndNotify.lock.notifyAll();
System.out.println("Notify进行通知了、也修改了条件,但是Wait不会马上从wait()返回继续执行,需要等待Notify释放锁,并且还得竞争到这个锁");
WaitAndNotify.sleepSecond(5);
System.out.println("Notify在通知后延迟了5秒释放了锁");
}synchronized(WaitAndNotify.lock) {
System.out.println("Notify的恶作剧,证明Wait接收到通知之后仍要竞争Lock才能从wait()方法返回继续执行");
}
}
}
输出:
Wait还未具备条件,等待
Notify进行通知了、也修改了条件,但是Wait不会马上从wait()返回继续执行,需要等待Notify释放锁,并且还得竞争到这个锁
Notify在通知后延迟了5秒释放了锁
Notify的恶作剧,证明Wait接收到通知之后仍要竞争Lock才能从wait()方法返回继续执行 这句不在最后输出出来说明本次执行Wait在得到通知之后竞争锁又被Notify抢走了
Wait获得了条件,执行业务逻辑
3、使用Condition配合Lock实现等待通知机制
packagecom.wangan.basic;importjava.util.concurrent.locks.Condition;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;public classConditionWaitAndNotify {public static Lock lock = newReentrantLock();public static Condition condition = lock.newCondition(); //Condition是依附于1个锁的
public static boolean flag = false;public static voidmain(String[] args) {new Thread(newConsumer()).start();try{
Thread.currentThread().sleep(2000);
}catch(InterruptedException e) {}new Thread(newProducer()).start();
}
}class Consumer implementsRunnable{
@Overridepublic voidrun() {
ConditionWaitAndNotify.lock.lock();//先拿到锁
try{while(!ConditionWaitAndNotify.flag) {
System.out.println("Consumer条件尚未具备,等待");
ConditionWaitAndNotify.condition.await();//在锁的Condition上等待
}
System.out.println("Consumer收到通知了、条件已具备,继续执行业务逻辑");
}catch(InterruptedException e) {
e.printStackTrace();
}finally{
ConditionWaitAndNotify.lock.unlock();
}
}
}class Producer implementsRunnable{
@Overridepublic voidrun() {
ConditionWaitAndNotify.lock.lock();try{
ConditionWaitAndNotify.flag= true;
ConditionWaitAndNotify.condition.signalAll();
System.out.println("Producer向Consumer通知条件已具备");
}finally{
ConditionWaitAndNotify.lock.unlock();
}
ConditionWaitAndNotify.lock.lock();//跟Consumer抢锁
System.out.println("Producer的恶作剧,发完通知用完了还跟Consumer抢一下锁");
ConditionWaitAndNotify.lock.unlock();
}
}
输出:
Consumer条件尚未具备,等待
Producer向Consumer通知条件已具备
Producer的恶作剧,发完通知用完了还跟Consumer抢一下锁
Consumer收到通知了、条件已具备,继续执行业务逻辑