Java技术——ReentrantLock的Condition的作用以及使用
来源:互联网 发布:python入门到精通 pdf 编辑:程序博客网 时间:2024/06/13 01:55
0. 前言
之前知道ReentrantLock类有一个newCondition(),用于获取Lock上的一个条件,还可以多次newCondition()获得多个条件,Condition可用于线程间通信。是对比ReentrantLock和Synchronized关键字的区别时学习到的。但是有次面试被问到有没有用到过ReentrantLock的Condition,瞬间懵逼了。所以搜集了些资料,通过一个小例子浅析一下ReentrantLock的Condition。总结出的结果就是:
(1)通过Condition能够更加精细的控制多线程的休眠与唤醒。
(2)对于一个锁,我们可以为多个线程间建立不同的Condition。
1. 使用Condition实现一个ArrayBlockingQueue
我们将实现的MyArrayBlockingQueue类需要包括以下功能:
(1)如果一个线程调用该类的take()获取元素时,若集合为空则使调用线程阻塞。直到有其他线程为集合加入新元素。
(2)如果一个线程调用该类的put()添加新元素时,若集合满了则使调用线程阻塞。直到有其他线程从集合充take出数据。
1.1 内部成员以及构造方法
从下面源码中可以看出,我们使用了泛型,并且默认使用长度为10的数组来维护数据集合。定义了一个锁,并且根据锁的lock.newCondition()创建了两个条件,分别对应集合满和集合空两个条件。
//维护的数据private final T[] datas;//数据的个数private int count;//插入取出的索引private int put_index;private int take_index;//锁private final Lock lock = new ReentrantLock();//定义两个条件,分别为“集合满”和“集合空”private Condition full = lock.newCondition();private Condition empty = lock.newCondition();//提供MyArrayBlockingQueue的构造方法,初始化T[]数据public MyArrayBlockingQueue() { this(10);}public MyArrayBlockingQueue(int maxSize) { this.datas = (T[]) new Object[maxSize];}
1.2 put/get方法
public void put(T data){ lock.lock(); try {if(count == datas.length){//此时集合已经满了System.out.println("集合已满,请等待...");//使调用线程挂起full.await();}//不满则添加新元素datas[put_index++] = data;count++;//此时唤醒等待取数据的线程empty.signalAll(); } catch (Exception e) {e.printStackTrace();}finally{lock.unlock();}}public T take(){lock.lock();try { if(count == 0){//此时集合已经空了System.out.println("集合已空,请等待...");//使调用线程挂起empty.await(); } //不空则取出最后一个数据 take_index = count - 1; T result = datas[take_index--]; count--; //此时唤醒等待写数据的线程 full.signalAll(); return result; } catch (Exception e) {e.printStackTrace();}finally{lock.unlock();}return null;}
put方法中,如果集合满了,就调用await()方法使对应的线程释放锁,并且使调用线程阻塞。直到其他线程调用了take()方法,并调用了full.signalAll()时,该请求线程会被精准唤醒,重新竞争到锁后,代码继续往下执行。
若集合不满,则添加新元素,并且通过empty.signalAll()精准唤醒等待取数据的线程。
可以看到在take方法中也是类似的逻辑。这样就灵活并且方便的使用Condition完成了一个简单的线程安全的阻塞队列,一些角标等细节没有处理,毕竟主角是Condition。
2. 总结
在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。Condition的强大之处在于,对于一个锁,我们可以为多个线程间建立不同的Condition。
如果采用Object类中的wait(), notify(), notifyAll()实现的话,当写入数据之后需要唤醒读线程时,不可能通过notify()或notifyAll()明确的指定唤醒读线程,而只能通过notifyAll唤醒所有线程,但是notifyAll无法区分唤醒的线程是读线程,还是写线程。所以,通过Condition能够更加精细的控制多线程的休眠与唤醒。
- Java技术——ReentrantLock的Condition的作用以及使用
- ReentrantLock 和 Condition的使用
- JAVA多线程-Lock的使用(一)-ReentrantLock与Condition
- Java多线程编程4--Lock的使用--重入锁(ReentrantLock)、Condition
- Java多线程11:ReentrantLock的使用和Condition
- Java并发编程 之 Condition与ReentrantLock的使用
- 线程锁ReentrantLock和Condition的使用
- 多线程锁的使用(ReentrantLock/Condition/ReentrantReadWriteLock)
- ReentrantLock类和Condition类的使用
- ReentrantLock的实现,加上Condition
- Java—Lock&Condition的使用
- join(),ReentrantLock结合Condition的await(),signal()的使用
- Java多线程(五) ReentrantLock、Lock和Condition的用法
- java并发控制:ReentrantLock Condition使用详解
- java 使用ReentrantLock Condition实现阻塞队列
- java并发控制:ReentrantLock Condition使用详解
- Java中Synchronized与ReentrantLock的不同以及ReentrantLock的使用
- ReentrantLock Condition使用详解
- http 代替 ajax原理解析
- 关于影印版与翻译版的对比
- oracle截取
- ZigBee 3.0 《Base-Device-Behavior-Specification》--Finding & binding initiator
- script脚本占位模板
- Java技术——ReentrantLock的Condition的作用以及使用
- emmc host调用mmc_rescan发现设备
- button控件的disable属性,很有用。是一种若隐若现,可见而不可点击的效果
- strust 标签 el表达式
- 二维码生成(图片居中)
- 脚本bo对象
- 二分搜索
- linux FONT
- js的return