java的java.util.concurrent.locks包内有Condition接口,该接口的官方定义以下:html
Condition
factors out the Object
monitor methods (wait
, notify
and notifyAll
) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitrary Lock
implementations. Where a Lock
replaces the use of synchronized
methods and statements, a Condition
replaces the use of the Object monitor methods.java
Conditions (also known as condition queues or condition variables) provide a means for one thread to suspend execution (to "wait") until notified by another thread that some state condition may now be true. Because access to this shared state information occurs in different threads, it must be protected, so a lock of some form is associated with the condition. The key property that waiting for a condition provides is that it atomically releases the associated lock and suspends the current thread, just like Object.wait
.api
咱们经过一个实际的例子来解释Condition的用法:并发
咱们要打印1到9这9个数字,由A线程先打印1,2,3,而后由B线程打印4,5,6,而后再由A线程打印7,8,9. 这道题有不少种解法,如今咱们使用Condition来作这道题(使用Object的wait,notify方法的解法在这里)。oracle
package cn.outofmemory.locks; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class App { static class NumberWrapper { public int value = 1; } public static void main(String[] args) { //初始化可重入锁 final Lock lock = new ReentrantLock(); //第一个条件当屏幕上输出到3 final Condition reachThreeCondition = lock.newCondition(); //第二个条件当屏幕上输出到6 final Condition reachSixCondition = lock.newCondition(); //NumberWrapper只是为了封装一个数字,一边能够将数字对象共享,并能够设置为final //注意这里不要用Integer, Integer 是不可变对象 final NumberWrapper num = new NumberWrapper(); //初始化A线程 Thread threadA = new Thread(new Runnable() { @Override public void run() { //须要先得到锁 lock.lock(); try { System.out.println("threadA start write"); //A线程先输出前3个数 while (num.value <= 3) { System.out.println(num.value); num.value++; } //输出到3时要signal,告诉B线程能够开始了 reachThreeCondition.signal(); } finally { lock.unlock(); } lock.lock(); try { //等待输出6的条件 reachSixCondition.await(); System.out.println("threadA start write"); //输出剩余数字 while (num.value <= 9) { System.out.println(num.value); num.value++; } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { try { lock.lock(); while (num.value <= 3) { //等待3输出完毕的信号 reachThreeCondition.await(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } try { lock.lock(); //已经收到信号,开始输出4,5,6 System.out.println("threadB start write"); while (num.value <= 6) { System.out.println(num.value); num.value++; } //4,5,6输出完毕,告诉A线程6输出完了 reachSixCondition.signal(); } finally { lock.unlock(); } } }); //启动两个线程 threadB.start(); threadA.start(); } }
上述代码中有完整的注释,请参考注释,理解Condition的用法。app
基本思路就是首先要A线程先写1,2,3,这时候B线程应该等待reachThredCondition信号,而当A线程写完3以后就经过 signal告诉B线程“我写到3了,该你了”,这时候A线程要等嗲reachSixCondition信号,同时B线程获得通知,开始写4,5,6,写 完4,5,6以后B线程通知A线程reachSixCondition条件成立了,这时候A线程就开始写剩下的7,8,9了。dom
为了更好的理解Condition的用法,咱们再看下java官方提供的例子:ide
package locks; import java.util.Random; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class AppOfficial { /** * BoundedBuffer 是一个定长100的集合,当集合中没有元素时,take方法须要等待,直到有元素时才返回元素 * 当其中的元素数达到最大值时,要等待直到元素被take以后才执行put的操做 * @author yukaizhao * */ static class BoundedBuffer { final Lock lock = new ReentrantLock(); final Condition notFull = lock.newCondition(); final Condition notEmpty = lock.newCondition(); final Object[] items = new Object[100]; int putptr, takeptr, count; public void put(Object x) throws InterruptedException { System .out.println("put wait lock"); lock.lock(); System.out.println("put get lock"); try { while (count == items.length) { System.out.println("buffer full, please wait"); notFull.await(); } items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } public Object take() throws InterruptedException { System.out.println("take wait lock"); lock.lock(); System.out.println("take get lock"); try { while (count == 0) { System.out.println("no elements, please wait"); notEmpty.await(); } Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } } } public static void main(String[] args) { final BoundedBuffer boundedBuffer = new BoundedBuffer(); Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("t1 run"); for (int i=0;i<1000;i++) { try { System.out.println("putting.."); boundedBuffer.put(Integer.valueOf(i)); } catch (InterruptedException e) { e.printStackTrace(); } } } }) ; Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i=0;i<1000;i++) { try { Object val = boundedBuffer.take(); System.out.println(val); } catch (InterruptedException e) { e.printStackTrace(); } } } }) ; t1.start(); t2.start(); } }
这个示例中BoundedBuffer是一个固定长度的集合,这个在其put操做时,若是发现长度已经达到最大长度,那么会等待notFull信 号,若是获得notFull信号会像集合中添加元素,并发出notEmpty的信号,而在其take方法中若是发现集合长度为空,那么会等待 notEmpty的信号,同时若是拿到一个元素,那么会发出notFull的信号。this