JAVA线程13 - 新特性:Lock和条件变量

1、Lock

1. 概述

Lock是JDK 1.5之后将同步和锁封装成了对象。Lock是对以前synchronized的替代。 
Lock接口的实现类:互斥锁ReentrantLock 。

2. synchronized与Lock区别 

synchronized对于锁的操做是隐式的;Lock锁对象是显式的。 
synchronized内只有一个锁。Lock能够有多个Conditoin。

3. 语法 

Lock myLock = new ReentrantLock(); 
myLock.lock();//获取锁 
try{ 
    //do something 
}finally{ 
    //释放锁。须要放在finally子句内,不然抛异常后,锁未被释放,其余线程则会永远被阻塞 
    myLock.unlock(); 
}

2、读写锁

1. 概述

为了提升性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在必定程度上提升了程序的执行效率。

读写锁分为读锁和写锁。多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。 java

Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock,也有具体的实现ReentrantReadWriteLock。 数据库

在实际开发中,最好在能用读写锁的状况下使用读写锁,而不要用普通锁,以求更好的性能。 缓存

2. 使用读写锁完成一个简单的缓存系统

public class SimpleCacheDemo{

    private Map<String, Object> cache = new HashMap<String, Object>();
    private ReadWriteLock rwlock = new ReentrantReadWriteLock();

    public Object getData(String key){
        rwlock.readLock().lock();
        Object obj = null;
        try{
            obj = cache.get(key);
            if(obj == null){
                rwlock.readLock().unlock();
                rolock.wirteLock().lock();
                try{
                    if(obj == null){
                        obj = queryDB(key);
                        if(obj != null){
                            cache.put(key, obj);
                            return obj;
                        }
                    }
                }finally{
                    rwlock.writeLock().unlock();
                }
                rwlock.readLock().lock();
            }
        }finally{
            rwlock.readLock().unlock();
        }
        return obj;
    }

    //从数据库查出值
    public Object queryDB(key){
        //todo
        return null;
    }
}

3、条件变量

条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是经过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。所以,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。  安全

条件变量的出现是为了更精细控制线程等待与唤醒,在Java5以前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细。 并发

Condition将Object监视器方法wait()、notify()、notifyAll()分解成大相径庭的对象,以便经过这些对象与任意Lock实现组合使用。 对应的方法是:await()、signal() 、signalAll() 。

4、使用JDK1.5后的新特性对多生产者与多消费者示例优化

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

/** 
* Java线程:并发协做-生产者消费者模型 
*/ 
public class ProducerConsumer { 
    public static void main(String[] args) { 
        Godown godown = new Godown(30); 
        Consumer c1 = new Consumer(50, godown); 
        Consumer c2 = new Consumer(20, godown); 
        Consumer c3 = new Consumer(30, godown); 
        Producer p1 = new Producer(10, godown); 
        Producer p2 = new Producer(10, godown); 
        Producer p3 = new Producer(50, godown); 
        Producer p4 = new Producer(10, godown); 
        Producer p5 = new Producer(70, godown); 


        c1.start(); 
        c2.start(); 
        c3.start(); 
        p1.start(); 
        p2.start(); 
        p3.start(); 
        p4.start(); 
        p5.start(); 
    } 
} 


/** 
* 仓库 
*/ 
class Godown { 
    public static final int max_size = 100; //最大库存量 
    public int curnum;     //当前库存量 
    
    private final Lock lock = new ReentrantLock();
    private final Condition connProduce = lock.newCondition();
    private final Condition connConsume = lock.newCondition();
    
    public Godown() { 
    } 

    public Godown(int curnum) { 
        this.curnum = curnum; 
    } 

    /** 
     * 生产指定数量的产品 
     * 
     * @param neednum 
     */ 
    public void produce(int neednum) { 
    lock.lock();
    try{
       //测试是否须要生产 
       while (neednum + curnum > max_size) { 
           System.out.println("要生产的产品数量" + neednum + "超过剩余库存量" + (max_size - curnum) + ",暂时不能执行生产任务!"); 
           try { 
               //当前的生产线程等待 
               connProduce.await();
           } catch (InterruptedException e) { 
               e.printStackTrace(); 
           } 
       } 
       //知足生产条件,则进行生产,这里简单的更改当前库存量 
       curnum += neednum; 
       System.out.println("已经生产了" + neednum + "个产品,现仓储量为" + curnum); 
       //唤醒在此对象监视器上等待的全部消费线程 
       connConsume.signalAll();
    }finally{
    lock.unlock();
    }
    } 

    /** 
     * 消费指定数量的产品 
     * 
     * @param neednum 
     */ 
    public void consume(int neednum) { 
    lock.lock();
    try{
       //测试是否可消费 
       while (curnum < neednum) { 
           try { 
               //当前的消费线程等待 
           	connConsume.await();
           } catch (InterruptedException e) { 
               e.printStackTrace(); 
           } 
       } 
       //知足消费条件,则进行消费,这里简单的更改当前库存量 
       curnum -= neednum; 
       System.out.println("已经消费了" + neednum + "个产品,现仓储量为" + curnum); 
       //唤醒在此对象监视器上等待的全部生产线程 
       connProduce.signalAll();
    }finally{
    lock.unlock();
    }
    } 
} 


/** 
* 生产者 
*/ 
class Producer extends Thread { 
    private int neednum;                //生产产品的数量 
    private Godown godown;            //仓库 

    Producer(int neednum, Godown godown) { 
        this.neednum = neednum; 
        this.godown = godown; 
    } 

    public void run() { 
        //生产指定数量的产品 
        godown.produce(neednum); 
    } 
} 


/** 
* 消费者 
*/ 
class Consumer extends Thread { 
    private int neednum;                //生产产品的数量 
    private Godown godown;            //仓库 

    Consumer(int neednum, Godown godown) { 
        this.neednum = neednum; 
        this.godown = godown; 
    } 

    public void run() { 
        //消费指定数量的产品 
        godown.consume(neednum); 
    } 
}
相关文章
相关标签/搜索