Condition的功能类似在传统线程技术中的 Object.wait() 和 Object.natify() 的功能,传统线程技术实现的互斥只能一个线程单独干,不能说这个线程干完了通知另一个线程来干,Condition就是解决这个问题的,实现线程间的通信。比如CPU让小弟做事,小弟说我先歇着先让大哥做并通知大哥,大哥就开始做事。
接口:public interface Condition
Condition 将 Object 监视器方法(wait、notify和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。
作为一个示例,假定有一个绑定的缓冲区,它支持 put 和 take 方法。如果试图在空的缓冲区上执行 take 操作,则在某一个项变得可用之前,线程将一直阻塞;如果试图在满的缓冲区上执行 put 操作,则在有空间变得可用之前,线程将一直阻塞。我们喜欢在单独的等待 set 中保存 put 线程和 take 线程,这样就可以在缓冲区中的项或空间变得可用时利用,一次只通知一个线程。可以使用两个 Condition 实例来做到这一点。
一个锁内部可以有多个Condition,即有多路等待和通知,可以参看jdk1.5提供的 Lock 与 Condition 实现的可阻塞队列的应用案例,从中除了要体味算法,还要体味面向对象的封装。
Condition使用案例之一:实现两个线程交替执行
1 import java.util.concurrent.ExecutorService; 2 import java.util.concurrent.Executors; 3 import java.util.concurrent.locks.Condition; 4 import java.util.concurrent.locks.Lock; 5 import java.util.concurrent.locks.ReentrantLock; 6 7 public class ConditionTest { 8 9 public static void main(String[] args) { 10 ExecutorService service = Executors.newSingleThreadExecutor(); 11 final Business2 business = new Business2(); 12 service.execute(new Runnable() {//提交5个business.sub方法任务到单个线程池中 13 public void run() { 14 for (int i = 0; i < 5; i++) { 15 business.sub(); 16 } 17 } 18 19 }); 20 21 for (int i = 0; i < 5; i++) {//执行5次business.main方法 22 business.main(); 23 } 24 } 25 26 } 27 28 class Business2 { 29 Lock lock = new ReentrantLock(); 30 Condition condition = lock.newCondition();//得到当前锁阻塞条件 31 boolean isSub = true; //默认一开始限制性sub任务 32 33 public void sub() { 34 lock.lock(); 35 if (!isSub) {//不是sub执行条件,则进入进行阻塞处理 36 try { 37 condition.await(); 38 } catch (InterruptedException e) { 39 e.printStackTrace(); 40 } 41 } 42 try { 43 for (int i = 0; i < 5; i++) { 44 System.out.println(Thread.currentThread().getName() + " : " + i); 45 } 46 isSub = false; 47 condition.signal(); 48 } finally { 49 lock.unlock(); 50 } 51 52 } 53 54 public void main() { 55 lock.lock(); 56 if (isSub) { //是sub执行任务,则进入阻塞main任务 57 try { 58 condition.await(); 59 } catch (InterruptedException e) { 60 e.printStackTrace(); 61 } 62 } 63 try { 64 for (int i = 0; i < 5; i++) { 65 System.out.println(Thread.currentThread().getName() + " : " + i); 66 } 67 isSub = true; 68 condition.signal(); 69 } finally { 70 lock.unlock(); 71 } 72 } 73 }
运行结果如下:
Condition使用案例之二:实现三个线程交替执行
1 import java.util.concurrent.locks.Condition; 2 import java.util.concurrent.locks.Lock; 3 import java.util.concurrent.locks.ReentrantLock; 4 5 public class SignalTest2 { 6 public static void main(String[] args) { 7 new SignalTest2().init(); 8 } 9 10 private void init() { 11 final Business b = new Business(); 12 new Thread() { 13 public void run() { 14 for (int i = 0; i < 5; i++) 15 b.sub1(); 16 } 17 }.start(); 18 19 new Thread() { 20 public void run() { 21 for (int i = 0; i < 5; i++) 22 b.sub2(); 23 } 24 }.start(); 25 26 new Thread() { 27 public void run() { 28 for (int i = 0; i < 5; i++) 29 b.sub3(); 30 } 31 }.start(); 32 } 33 34 private class Business { 35 int status = 1;//开始默认执行第一个方法 36 Lock lock = new ReentrantLock(); 37 Condition cond1 = lock.newCondition(); 38 Condition cond2 = lock.newCondition(); 39 Condition cond3 = lock.newCondition(); 40 41 public void sub1() { 42 lock.lock(); 43 while (status != 1) { 44 try { 45 cond1.await(); 46 } catch (Exception e) { 47 } 48 } 49 for (int i = 1; i <= 5; i++) { 50 try { 51 Thread.sleep(200); 52 } catch (Exception e) {} 53 System.out.println("[sub1]" + Thread.currentThread().getName() + ":" + i); 54 } 55 status = 2;//1执行完指定2开始执行 56 cond2.signal(); 57 lock.unlock(); 58 } 59 60 public void sub2() { 61 lock.lock(); 62 while (status != 2) { 63 try { 64 cond2.await(); 65 } catch (Exception e) { 66 } 67 } 68 for (int i = 1; i <= 5; i++) { 69 try { 70 Thread.sleep(200); 71 } catch (Exception e) {} 72 System.out.println("[sub2]" + Thread.currentThread().getName() + ":" + i); 73 } 74 status = 3;//2执行完指定3开始执行 75 cond3.signal(); 76 lock.unlock(); 77 } 78 79 public void sub3() { 80 lock.lock(); 81 while (status != 3) { 82 try { 83 cond3.await(); 84 } catch (Exception e) { 85 } 86 } 87 for (int i = 1; i <= 5; i++) { 88 try { 89 Thread.sleep(200); 90 } catch (Exception e) { 91 } 92 System.out.println("[sub3]" + Thread.currentThread().getName() + ":" + i); 93 } 94 status = 1;//3执行完指定1开始执行 95 cond1.signal(); 96 lock.unlock(); 97 } 98 } 99 }
运行结果如下:
提示:欢迎继续参看我相关的下一篇博客:并发库应用之七 & 信号灯Semaphore应用