在上一篇博文中跟大家分享了java juc包中的lock锁的lock、tryLock、tryLock(带超时时间的)、lockInterruptibly这四个方法。
这里要和大家分享的是java juc包中的lock锁的newCondition()方法,我这里写了一段基于Condition的ReentrantLock 实现的阻塞队列的读写锁操作,废话少说,直接看代码
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 基于Condition的ReentrantLock 阻塞队列操作
* @author tongke
* @email tongkp@126.com
* @create 2020-07-23 23:10
*/
public class BlockingQueue_Demo {
public static void main(String[] args) throws InterruptedException {
final AppinBlockingQueue appinBlockingQueue = new AppinBlockingQueue(5);
new Thread(){
@Override
public void run() {
System.out.println("开始插入元素");
for (int i = 0; i < 20; i++) {
appinBlockingQueue.put("t"+i);
}
}
}.start();
Thread.sleep(1000L);
System.out.println("开始取元素");
for (int i = 0; i < 10; i++) {
appinBlockingQueue.take();
Thread.sleep(2000);
}
}
}
/**
* 阻塞队列
*/
class AppinBlockingQueue{
List<Object> list = new ArrayList<Object>(); //容器
private Lock lock = new ReentrantLock(); //声明锁
private Condition putCondition = lock.newCondition(); //condition可以有多个,针对不同的操作放入不同的condition,相当于等待队列
private Condition takeCondition = lock.newCondition();
private int length; //队列的长度
public AppinBlockingQueue(int length) {
this.length = length;
}
//写入
public void put(Object obj){
lock.lock();
try {
while (true){
if(list.size() < length){ //集合的长度不能超过设定的长度
list.add(obj);
System.out.println("队列中放入元素:"+obj);
takeCondition.signal(); //队列中有数据了,唤醒取数据的线程
return;
}else { //队列已满,放不进了,利用condition进行阻塞
putCondition.await(); //挂起
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//读取
public Object take(){
lock.lock();
try {
while (true){
if (list.size() > 0){
Object obj = list.remove(0);
System.out.println("队列中取得元素:"+obj);
putCondition.signal(); //唤醒插入线程
return obj;
}else { //队列中已经没有数据了
takeCondition.await(); //挂起
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
return null;
}
}
}
我们通过了一段简单的代码可以了解到,根据业务的需要我们可以有多个condition,每个condition都对应着一个await()挂起方法和一个signal()唤醒方法。
要特别注意的是这里的挂起方法await()和wait()很像,但实际相差甚远,关于wait()的特性不了解的可以自行查看相关的资料,这里一旦不注意写错,会在运行时报一个Exception in thread "Thread-0" java.lang.IllegalMonitorStateException的错误。
水平有限,欢迎交流指正。