通过ReentrantLock与Condition的设计,以数组为基础,可以实现简单的队列和栈的数据结构,临界阻塞的效果。

ReentrantLock相对于synchronized比较大的一个区别是有条件变量:Condition,很大一个程度上是为了解决Object.wait/notify/notifyAll难以使用的问题。Condition(也称为条件队列 或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为 true 的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它必须受保护,因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是:以原子方式 释放相关的锁,并挂起当前线程,就像 Object.wait 做的那样。多个Condition需要绑定到同一锁上,可以实现队列与栈。

队列:先进先出的原则

栈:先进后出的原则

类一:模拟队列的读写操作

 package reentranlock;

 import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class BoundedBufferQueue { static Lock lock = new ReentrantLock();
static Condition read = lock.newCondition();
static Condition write = lock.newCondition();
static Object [] data = new Object [10];// 构造一个缓存队列 private static int count = 0;// 用来标识队列中存放的数据量
private static int readIndex = 0;// 标识读取的下标
private static int writeIndex = 0;// 标识写入的下标 public static void put(Integer num) throws InterruptedException {
try {
lock.lock();
if (count == 10) {
write.await();// 数据量满了则阻塞写的操作
}
data[writeIndex] = num;
count++;
if (++writeIndex == 10) {// 循环写入数据
writeIndex = 0;
}
read.signal();// 触发读操作
} finally {
lock.unlock();
}
} public static Object take() throws InterruptedException {
Object result = null;
try {
lock.lock();
if (count == 0) {// 如果队列无数据量则阻塞读操作
read.await();
}
result = (Integer) data[readIndex];
count--;
if (++readIndex == 10) {// 循环取数据
readIndex = 0;
}
write.signal();// 触发写操作
} finally {
lock.unlock();
}
return result;
} // 下面是模拟读写操作过程,可以通过操作时间不同来验证队列读取。
public static void main(String[] args) throws InterruptedException { Runnable readThread = new Runnable() {
@Override
public void run() {
while(true){
for(int i=1;i<Integer.MAX_VALUE;i++){
try {
Integer o = (Integer) take();
System.out.println("读取:"+o);
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
}; Runnable writeThread = new Runnable() {
@Override
public void run() {
while(true){
for(int i=1;i<Integer.MAX_VALUE;i++){
try {
put(i);
System.out.println("写入:"+i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
}; Thread read = new Thread(readThread);
Thread write = new Thread(writeThread); read.start();
Thread.currentThread().join(1000);
write.start();
} }

类二:模拟栈的读写操作

 package reentranlock;

 import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class BoundedBufferStack { static Lock lock = new ReentrantLock();
static Condition read = lock.newCondition();
static Condition write = lock.newCondition();
static Object [] data = new Object [10];// 构造一个缓存栈 private static int count = 0;// 用来标识栈中存放的数据量
private static int index = 0;// 标识的下标 public static void put(Integer num) throws InterruptedException {
try {
lock.lock();
if (count == 10) {// 数据量满了则阻塞写操作
write.await();
}
data[index] = num;
count++;
index++;
if (index == 10) {
index = 0;
}
read.signal();// 触发读操作
} finally {
lock.unlock();
}
} public static Object take() throws InterruptedException {
Object result = null;
try {
lock.lock();
if (count == 0) {// 数据量为空则阻塞读操作
read.await();
}
if(index == 0 && count == 10){// 为了仿造栈的后进先出的模式,取最后写入的数据
index = 9;
}else{
index --;
}
result = (Integer) data[index];
count--;
if (index == 0) {
index = 0;
}
write.signal();// 触发写操作
} finally {
lock.unlock();
}
return result;
} // 下面是模拟读写操作过程,可以通过操作时间不同来验证栈的读取。
public static void main(String[] args) throws InterruptedException { Runnable readThread = new Runnable() {
@Override
public void run() {
while(true){
for(int i=1;i<Integer.MAX_VALUE;i++){
try {
Integer o = (Integer) take();
System.out.println("读取:"+o);
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
}; Runnable writeThread = new Runnable() {
@Override
public void run() {
while(true){
for(int i=1;i<Integer.MAX_VALUE;i++){
try {
put(i);
System.out.println("写入:"+i);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
}; Thread read = new Thread(readThread);
Thread write = new Thread(writeThread); write.start();
Thread.currentThread().join(1000);
read.start();
} }

ArrayBlockingQueue也是这种设计 "通过平衡生产者和消费者的处理能力来提高整体处理数据的速度",只不过运用ArrayBlockingQueue不要担心非单一生产者/消费者场景下的系统假死问题,缓冲区空、缓冲区满的场景BlockingQueue都是定义了不同的Condition,所以不会唤醒自己的同类。

ReentrantLock与Condition构造有界缓存队列与数据栈的更多相关文章

  1. 使用 ReentrantLock 和 Condition 实现一个阻塞队列

    前言 从之前的阻塞队列的源码分析中,我们知道,JDK 中的阻塞队列是使用 ReentrantLock 和 Condition 实现了,我们今天来个简易版的.代码如下: 代码 public class ...

  2. 【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列

    package cn.study.concurrency.ch14; import java.util.concurrent.locks.Condition; import java.util.con ...

  3. Java多线程之wait、notify/notifyAll 详解,用wait 和notifyAll 以及synchronized实现阻塞队列,多线程拓展之ReentrantLock与Condition

    前言:这几天看了很多关于多线程的知识,分享一波.(但是目前接触的项目还未用到过,最多用过线程池,想看线程池 请看我之前的博客) 关于基本的理论等 参考如下: https://www.cnblogs.c ...

  4. 类 ArrayBlockingQueue<E>(一个由数组支持的有界阻塞队列。)

    类型参数: E - 在此 collection 中保持的元素类型 所有已实现的接口: Serializable, Iterable<E>, Collection<E>, Blo ...

  5. 【JAVA并发编程实战】11、有界缓存的实现

    1.有界缓存的基类 package cn.xf.cp.ch14; /** * *功能:有界缓存实现基类 *时间:下午2:20:00 *文件:BaseBoundedBuffer.java *@autho ...

  6. 使用lock和condition实现的阻塞队列-字符串

    在jdk 的API中提供了一个字符串的阻塞队列 : class BoundedBuffer { final Lock lock = new ReentrantLock(); final Conditi ...

  7. Java多线程之ReentrantLock与Condition

    一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...

  8. ReentrantLock和condition源码浅析(二)

    转载请注明出处... 接着上一篇的ReentrantLock和condition源码浅析(一),这篇围绕着condition 一.condition的介绍 在这里为了作对比,引入Object类的两个方 ...

  9. 使用ReentrantLock和Condition来代替内置锁和wait(),notify(),notifyAll()

    使用ReentrantLock可以替代内置锁,当使用内置锁的时候,我们可以使用wait() nitify()和notifyAll()来控制线程之间的协作,那么,当我们使用ReentrantLock的时 ...

随机推荐

  1. rtmp流媒体搭建的所需安装包

    说明:这是基于nginx rtmp控件  搭建的rtmp流媒体服务器,在此附上的是搭建所需要的安装包,具体的搭建过程看我之前的"ubuntu流媒体搭建" 链接地址:http://p ...

  2. java进程脱离终端运行

    关于 java 进程脱离终端放入后台运行的问题,首先想到是使用nohup命令: 研究了一下tomcat启动脚本.jenkins.war启动方式以及其他linux命令,结论是在目前的linux系统上不使 ...

  3. Ajax 的用法

    1.什么是 Ajax? Ajax,英文名 Asynchronous JavaScript and XML,也就是异步的 JavaScript 和 XML.它不是一门新的语言,而是一种使用现有标准的新方 ...

  4. Xamarin.Android 引导页

    http://blog.csdn.net/qq1326702940/article/details/78665588 https://www.cnblogs.com/catcher1994/p/555 ...

  5. @Autowired内部实现原理

    @Autowiredprivate CustomerDao customerDao;        public void addCustomer() {        customerDao.add ...

  6. vue的挖坑和爬坑之vuex的简单入门

    首先vuex的中文文档https://vuex.vuejs.org/zh-cn/ 首先vuex是什么,官方解释是 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应 ...

  7. ASP.NET Core学习之四 在CentOS上部署.net core

    一.安装CentOs 以前在大学学过linux,但是对命令行总是有一种深深的排斥感,几年之后,还是又回来了. 1.下载 现在没法FQ,就算是FQ网速也是蜗牛一样慢,我使用阿里云的镜像站进行下载速度还是 ...

  8. Head First设计模式之工厂模式

    一.定义 定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个. 工厂方法让类把实例化推迟到子类 二.结构 1.抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关.是具体工厂角色必须实现的 ...

  9. [总结]-2018 w1

    不想总结 2017,过去的就过去吧,不过自己在 2017 年还是收获了很多,最重要的就是赚钱.赚钱还是需要两把刷子,所以,2018 的小目标就是学习数据分析和机器学习.希望自己在这两个领域能搞点事情. ...

  10. HTML 中有用的字符实体

    HTML 中有用的字符实体