欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java并发编程(十三)- 显示锁使用Lock和Condition实现等待通知模式

程序员文章站 2024-01-08 09:00:52
...

通常在开发并发程序的时候,会碰到需要停止正在执行业务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的线程有用。