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的时 ...
随机推荐
- chattr 命令详解
chattr 作用: 改变文件属性,这项指令可改变存放在ext2文件系统上的文件或目录属性,这些属性共有一下8种模式 模式: a: 让文件或目录仅供附加用途 b: 不更新文件或目录的最后存取时间 ...
- js构建函数,点击按钮显示div,再点击按钮或其他区域,隐藏div
这只是一个例子,先看看效果: html代码: <nav> <span class="nav_logo"></span> <h1>云蚂 ...
- js控制图片自动缩放,实现铺满盒子,不变形,完全局中
此js一般用于控制图片铺满盒子,但是比例不变,并且绝对局中原理:判断图片的高宽与盒子高宽的大小的关系,然后通过比例来控制图片的缩放及定位<!DOCTYPE html PUBLIC "- ...
- linux mysql添加、删除用户、用户权限及mysql最大字段数量
1. 登录: mysql -u username -p 显示全部的数据库: show databases; 使用某一个数据库: use databasename; 显示一个数据库的全部表: show ...
- K:java中properties文件的读写
Properties类与.properties文件: Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存属性集的类,不过Properties有特殊 ...
- 笔记-NSArray 逆序reverseObjectEnumerator 及 NSEnumerator 遍历
//1.原始数组 NSMutableArray *array = [NSMutableArray arrayWithObjects:@"1",@"2",@&qu ...
- Android View的事件冲突
上一篇博客讨论了一下view中的事件分发,既然存在事件分发的过程,那么也就可能存在着冲突.常见的由以下三种形式的冲突.(外面叫做OuterViewGroup,包裹在里面的叫做InnerViewGrou ...
- zabbix 3.0.4 中文字体替换
zabbix 对中文支持不是很好,会出现乱码: 从windows系统里 找到字体包:如图: 拷贝到zabbix-server里面,注意,把文件名改成小写: 我linux 是centos7.2版本 [r ...
- python 模块:xlrd && xlwt
主要来自:http://www.jb51.net/article/60510.htm python读excel--xlrd 这个过程有几个比较麻烦的问题,比如读取日期.读合并单元格内容.下面先看看基本 ...
- Celery(三)实例Application
Celery必须实例化后才可以使用,实例称之为application或者简称app.实例是线程安全的,多个Celery实例(不同的配置.部件和任务)都可以在一个进程空间中运行. 创建一个最简单的app ...