ReentrantLock与Condition构造有界缓存队列与数据栈
通过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构造有界缓存队列与数据栈的更多相关文章
- 使用 ReentrantLock 和 Condition 实现一个阻塞队列
前言 从之前的阻塞队列的源码分析中,我们知道,JDK 中的阻塞队列是使用 ReentrantLock 和 Condition 实现了,我们今天来个简易版的.代码如下: 代码 public class ...
- 【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列
package cn.study.concurrency.ch14; import java.util.concurrent.locks.Condition; import java.util.con ...
- Java多线程之wait、notify/notifyAll 详解,用wait 和notifyAll 以及synchronized实现阻塞队列,多线程拓展之ReentrantLock与Condition
前言:这几天看了很多关于多线程的知识,分享一波.(但是目前接触的项目还未用到过,最多用过线程池,想看线程池 请看我之前的博客) 关于基本的理论等 参考如下: https://www.cnblogs.c ...
- 类 ArrayBlockingQueue<E>(一个由数组支持的有界阻塞队列。)
类型参数: E - 在此 collection 中保持的元素类型 所有已实现的接口: Serializable, Iterable<E>, Collection<E>, Blo ...
- 【JAVA并发编程实战】11、有界缓存的实现
1.有界缓存的基类 package cn.xf.cp.ch14; /** * *功能:有界缓存实现基类 *时间:下午2:20:00 *文件:BaseBoundedBuffer.java *@autho ...
- 使用lock和condition实现的阻塞队列-字符串
在jdk 的API中提供了一个字符串的阻塞队列 : class BoundedBuffer { final Lock lock = new ReentrantLock(); final Conditi ...
- Java多线程之ReentrantLock与Condition
一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...
- ReentrantLock和condition源码浅析(二)
转载请注明出处... 接着上一篇的ReentrantLock和condition源码浅析(一),这篇围绕着condition 一.condition的介绍 在这里为了作对比,引入Object类的两个方 ...
- 使用ReentrantLock和Condition来代替内置锁和wait(),notify(),notifyAll()
使用ReentrantLock可以替代内置锁,当使用内置锁的时候,我们可以使用wait() nitify()和notifyAll()来控制线程之间的协作,那么,当我们使用ReentrantLock的时 ...
随机推荐
- MySQL连接方式及大小写问题
一.连接数据库 在命令行连接MySQL有这两种方式,一种是使用命令行参数:另一种是将参数信息写入配置文件 1.命令行中使用参数 -u用户名 -p密码 -D数据库名 -P数据库服务端口 -s安静模式 ...
- 再谈javascript面向对象编程
前言:虽有陈皓<Javascript 面向对象编程>珠玉在前,但是我还是忍不住再画蛇添足的补上一篇文章,主要是因为javascript这门语言魅力.另外这篇文章是一篇入门文章,我也是才开始 ...
- Unity 3d游戏逆向及.NET Reflector工具使用介绍
移动平台游戏框架主要有unity 3d和cocos 2d.我们首先得识别游戏使用的框架.识别Unity游戏Android平台的apk包可以直接解压,看是否有./assets/bin/Data/Mana ...
- python的range()函数
range函数的三种用法:>>> range(1,5) # 代表从1到5(不包含5) [1, 2, 3, 4] >>> range(1,5,2) # 代表从1到5, ...
- HTML5图片上传本地预览
在开发 H5 应用的时候碰到一个问题,应用只需要一张小的缩略图,而用户用手机上传的确是一张大图,手机摄像机拍的图片好几 M,这可要浪费很多流量. 我们可以通过以下方式来解决. 获取图片 通过 File ...
- Java学习笔记-枚举类型
枚举类型 枚举类型就是预先定义的一类常量集合,如一周的时间.水果的类型等.需要注意的几点内容如下: 定义枚举类时,Java默认继承java.lang.Enum,所以定义的枚举类不能继承其他类型: 枚举 ...
- Celery(四)定时任务
要定时或者周期性的执行任务,可以使用linux的crontab.Celery也提供了类似的Periodic Tasks功能. Celery beat Celery使用celery beat作为任务调度 ...
- python3基础(七)函数基础
Function 函数是一段组织好的能够实现特定功能或者逻辑的代码块,函数代码在文件执行时读入内存并不执行,在调用函数时执行,简单来说是把一段代码封装给一个函数名(可以用变量的概念去理解,即把一段代码 ...
- .NET Core RSA密钥的xml、pkcs1、pkcs8格式转换和JavaScript、Java等语言进行对接
众所周知在.NET下的RSA类所生成的密钥为Xml格式,而其他语言比如java一般使用pkcs8格式的密钥,JavaScript一般使用pkcs1格式.我们在开发过程中很可能遇到需要与其他语言开发的a ...
- [代码审计]青云客Cms前台有条件注入至getshell,后台xss至getshell、至弹你一脸计算器
之前写了一篇关于青云客cms的文章,发在了t00ls,就不copy过来了. 给个链接,好记录一下. https://www.t00ls.net/thread-43093-1-1.html