通常在开发并发程序的时候,会碰到需要停止正在执行业务A,来执行另一个业务B,当业务B执行完成后业务A继续执行。ReentrantLock通过Condtion等待/唤醒这样的机制.

相比较synchronize的wait()和notify()/notifAll()的机制而言,Condition具有更高的灵活性,这个很关键。Conditon可以实现多路通知和选择性通知。

当使用notify()/notifAll()时,JVM时随机通知线程的,具有很大的不可控性,所以建议使用Condition。

 

package com.caojiulu;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
*
*@author caojiulu
*
*类说明:
*/
public class ExpressCond {
public final static String CITY = "ShangHai";
private int km;/*快递运输里程数*/
private String site;/*快递到达地点*/
private Lock lock = new ReentrantLock();
private Condition keCond = lock.newCondition();
private Condition siteCond = lock.newCondition();

public ExpressCond() {
}

public ExpressCond(int km, String site) {
this.km = km;
this.site = site;
}

/* 变化公里数,然后通知处于wait状态并需要处理公里数的线程进行业务处理*/
public void changeKm(){
lock.lock();
try {
this.km = 101;
keCond.signalAll();
}finally {
lock.unlock();
}
}

/* 变化地点,然后通知处于wait状态并需要处理地点的线程进行业务处理*/
public void changeSite(){
lock.lock();
try {
this.site = "BeiJing";
siteCond.signal();
}finally {
lock.unlock();
}
}

/*当快递的里程数大于100时更新数据库*/
public void waitKm(){
lock.lock();
try {
while(this.km<=100) {
try {
keCond.await();
System.out.println("check km thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}

System.out.println("the Km is "+this.km+",I will change db");
}

/*当快递到达目的地时通知用户*/
public void waitSite(){
lock.lock();
try {
while(CITY.equals(this.site)) {
try {
siteCond.await();
System.out.println("check site thread["+Thread.currentThread().getId()
+"] is be notifed.");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}finally {
lock.unlock();
}
System.out.println("the site is "+this.site+",I will call user");
}
}

测试类:

package com.caojiulu;

/**
*@author caojiulu
*
*类说明:测试Lock和Condition实现等待通知
*/
public class TestCond {
private static ExpressCond express = new ExpressCond(0,ExpressCond.CITY);

/*检查里程数变化的线程,不满足条件,线程一直等待*/
private static class CheckKm extends Thread{
@Override
public void run() {
express.waitKm();
}
}

/*检查地点变化的线程,不满足条件,线程一直等待*/
private static class CheckSite extends Thread{
@Override
public void run() {
express.waitSite();
}
}

public static void main(String[] args) throws InterruptedException {
for(int i=0;i<3;i++){
new CheckSite().start();
}
for(int i=0;i<3;i++){
new CheckKm().start();
}

Thread.sleep(1000);
express.changeKm();//快递里程变化
}
}

分别实例化了两个Condition对象,都是使用同一个lock注册。注意keCond对象的等待和唤醒只对使用了keCond的线程有用,同理siteCond对象的等待和唤醒只对使用了siteCond的线程有用。