Condition
将 Object
监视器方法(wait
、notify
和 notifyAll
)分解成截然不同的对象,以便通过将这些对象与任意 Lock
实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock
替代了 synchronized
方法和语句的使用,Condition
替代了 Object 监视器方法的使用。
Condition
实例实质上被绑定到一个锁上。要为特定 Lock
实例获得 Condition
实例,请使用其 newCondition()
方法。Condition
实现可以提供不同于 Object
监视器方法的行为和语义,比如受保证的通知排序,或者在执行通知时不需要保持一个锁。
情景一:三个线程,线程1打印A,线程2打印B,线程3打印C
public class ThreeRun {public void printB() {System.out.println("B");}public void printA() {System.out.println("A");}public void printC() {System.out.println("C");}public static void main(String[] args) {ThreeRun threeRun = new ThreeRun();A a = new A(threeRun);B b = new B(threeRun);C c = new C(threeRun);new Thread(a).start();new Thread(b).start();new Thread(c).start();}static class A implements Runnable {private ThreeRun threeRun;public A(ThreeRun threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printA();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}static class B implements Runnable {private ThreeRun threeRun;public B(ThreeRun threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printB();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}static class C implements Runnable {private ThreeRun threeRun;public C(ThreeRun threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printC();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}}
场景二、三个线程,线程1打印A,线程2打印B,线程3打印C (保证顺序打印,ABCABC....)
public class ThreeRun2 {//用作判断的信号 0执行A,1执行B,2执行Cprivate int single=0;public synchronized void printB() {while (single!=1){try {//本线程等待 释放锁wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("B");//增量,保证顺序性single++;//通知其他的线程notifyAll();}public synchronized void printA() {while (single!=0){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("A");single++;notifyAll();}public synchronized void printC() {while (single!=2){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("C");//为保证紧接着打印A,将增量清零single=0;notifyAll();}public static void main(String[] args) {ThreeRun2 threeRun = new ThreeRun2();A a = new A(threeRun);B b = new B(threeRun);C c = new C(threeRun);new Thread(a).start();new Thread(b).start();new Thread(c).start();}static class A implements Runnable {private ThreeRun2 threeRun;public A(ThreeRun2 threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printA();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}static class B implements Runnable {private ThreeRun2 threeRun;public B(ThreeRun2 threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printB();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}static class C implements Runnable {private ThreeRun2 threeRun;public C(ThreeRun2 threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printC();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}}
场景三、三个线程,线程1打印A,线程2打印B,线程3打印C (保证顺序打印,ABCABC.... 换用condition的方式实现)
public class ThreeRun3 {private int single=0;//Condition是一个接口,在ReentrantLock里有实现Lock lock=new ReentrantLock();//分别获取三个条件锁Condition a=lock.newCondition();Condition b=lock.newCondition();Condition c=lock.newCondition();public void printB() {lock.lock();while (single!=1){try {//相当于Object的wait()b.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("B");single++;//相当于nodifyAll()c.signal();lock.unlock();}public void printA() {lock.lock();while (single!=0){try {a.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("A");single++;b.signal();lock.unlock();}public void printC() {lock.lock();while (single!=2){try {c.await();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("C");single=0;a.signal();lock.unlock();}public static void main(String[] args) {ThreeRun3 threeRun = new ThreeRun3();A a = new A(threeRun);B b = new B(threeRun);C c = new C(threeRun);new Thread(a).start();new Thread(b).start();new Thread(c).start();}static class A implements Runnable {private ThreeRun3 threeRun;public A(ThreeRun3 threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printA();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}static class B implements Runnable {private ThreeRun3 threeRun;public B(ThreeRun3 threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printB();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}static class C implements Runnable {private ThreeRun3 threeRun;public C(ThreeRun3 threeRun) {this.threeRun = threeRun;}@Overridepublic void run() {while (true) {threeRun.printC();try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}}}}
使用说明:这个是API中给出的实例说明
condition要和Lock锁的实现类一起使用。
unlock()要与finally代码块一起使用。
await()要与Object的wait()区分开。
Condition是一个接口,在ReentrantLock里面的Sync用到了。它的实现类其实在AbstractQueuedSynchronizer里面的ConditionObject内部类。而该实现类里面有使用到了AQS的另一个内部类Node,这是一个双向链表的数据结构实现类。真是一环扣一环啊,condition使用虽然简单,但是当初实现它时并不简单。如果有很好的数据结构基础,读这个源码应该轻松一些。但是我感觉有点吃力,等恶补了数据结构这方面后,再回来补充condition的源码剖析。