java 多线程 条件变量_JAVA线程13 - 新特性:Lock和条件变量

一、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();

}

二、读写锁

1. 概述 为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,在一定程度上提高了程序的执行效率。

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

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

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

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

public class SimpleCacheDemo{

private Map cache = new HashMap();

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;

}

}

三、条件变量

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

条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细。 Condition将Object监视器方法wait()、notify()、notifyAll()分解成截然不同的对象,以便通过这些对象与任意Lock实现组合使用。 对应的方法是:await()、signal() 、signalAll() 。

四、使用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);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值