synchronized中也有条件变量,就是Monitor对象中的WaitSet,当线程条件不满足/调用wait方法后会进入WaitSet中等待
ReentrantLock的条件变量比synchronized强大之处在于,它支持多个条件变量,这就好比:
- synchronized是那些不满足条件的线程都在一间休息室等消息
 - ReentrantLock支持多件休息室,有专门等烟的休息室,专门等早餐的休息室,唤醒时也是按休息室来唤醒
 
使用流程(与synchronized的wait-notify方法对比记忆)
- await前需要获得锁(与wait方法类似)
 - await执行后,会释放锁,进入conditionObject等待
 - await的线程被唤醒、打断、超时后会重新竞争lock锁(与synchronized类似,例如从WaitSet中进入EntryList中竞争锁)
 - 竞争lock锁成功后,从await处的代码继续向后执行。(这里也复习一下wait方法,当被唤醒、打断、超时后进入EntryList,只有重新竞争到锁才会继续从wait代码处向下执行完毕,可以理解为wait-notify本身就是在synchronized块内的,如果再次执行也势必要重新获得锁)
 
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class TestCondition {static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {//创建一个新的条件变量(休息室)Condition condition1 = lock.newCondition();Condition condition2 = lock.newCondition();lock.lock();//主线程先获得锁//进入休息室中condition1.await();//主线程在condition1中等待}}
创建条件变量:
Condition condition1 = lock.newCondition();
线程在条件变量上等待:
condition1.await()
唤醒线程:
//随机唤醒在condition1对象上等待的一个线程condition1.signal();//唤醒在condition1对象上等待的所有线程condition1.signalAll();
送烟送外卖例子改为如下代码:
import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class TestCondition {static ReentrantLock ROOM = new ReentrantLock();//创建锁对象static Condition waitCigaretteSet = ROOM.newCondition();//等待烟的队列static Condition waitTakeoutSet = ROOM.newCondition();//等待外卖的队列static boolean hasCigarette = false;//有没有烟static boolean hasTakeout = false;//有没有外卖public static void main(String[] args) throws InterruptedException {new Thread(()->{ROOM.lock();try{System.out.println("有烟没?"+hasCigarette);while(!hasCigarette){System.out.println("没烟,先歇会儿");try {waitCigaretteSet.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("有烟没?"+hasCigarette);if(hasCigarette){System.out.println("可以开始干活了");}else{System.out.println("没干成活");}}finally {ROOM.unlock();}},"小南").start();new Thread(()->{ROOM.lock();try{System.out.println("外卖送到没?"+hasTakeout);while(!hasTakeout){System.out.println("外卖没到呢,等着吧您");try {waitTakeoutSet.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("外卖到没"+hasTakeout);if(hasCigarette){System.out.println("吃上外卖了");}else{System.out.println("饿死我了,还没吃上外卖");}}finally {ROOM.unlock();}},"小女").start();Thread.sleep(1000);//睡眠1秒//送外卖线程new Thread(()->{ROOM.lock();//还是先获得锁,signal方法也要在获得锁的情况下使用try{hasTakeout=true;waitTakeoutSet.signal();//唤醒等待线程System.out.println("外卖送到了嗷!");}finally {ROOM.unlock();}},"送外卖的").start();Thread.sleep(1000);//睡眠1秒//送烟线程new Thread(()->{ROOM.lock();//还是先获得锁,signal方法也要在获得锁的情况下使用try{hasCigarette=true;waitCigaretteSet.signal();//唤醒等待线程System.out.println("烟送到了嗷!");}finally {ROOM.unlock();}},"送烟的").start();}}
实际上与synchronized的wait-notify写法的逻辑一模一样,只是语法不同。
