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的时 ...
随机推荐
- OpenStack运维(一):OpenStack项目和用户
1.添加项目 keystone tenant-create --name=demo [--description tenant-description --enable false] demo:项目名 ...
- [解决方案]WebAPI+SwaggerUI部署服务器后,访问一直报错的问题
项目的背景:制作一批接口用来给前台app或者网站提供服务,因为WebApi是最近几年来比较流行和新颖的开发接口的方式,而且又属于轻型应用,所以选用它 部署的过程:建立了WebAPI项目并使用Swagg ...
- Linux(CentOS6.5_X86.64)编译libjpeg出现“checking host system type... Invalid configuration `x86_64-unknown-linux-gnu': machine `x86_64-unknown' not recognized”的解决
本文地址http://comexchan.cnblogs.com/,作者Comex Chan,尊重知识产权,转载请注明出处,谢谢! 今天在编译libjpeg 的时候,遇到下面的报错: checki ...
- 初学者福音——10个最佳APP开发入门在线学习网站
根据Payscale的调查显示,现在的APP开发人员的年薪达到:$66,851.这也是为什么那么多初学的开发都想跻身到APP开发这行业的主要原因之一.每当你打开App Store时候,看着琳琅满目的A ...
- LindDotNetCore~基于模块化注入的介绍
LindDotNetCore相关介绍 相关模块 全局都是依赖DI 消息队列 NoSql Caching 仓储 服务总线 Solr 调度 日志 Asspect拦截组件 UAA授权 各种组件环境的搭建 各 ...
- js选中文字兼容性解决
function selectText(){ if(document.selection){ //ie return document.selection.createRange().text; } ...
- 跟我一起学JQuery插件开发教程
在逛codeproject网站的时候,突然看到一篇文章:How to write plugin in Jquery. 如果对E文好的同学 ,可以看上面的连接.现在我把上面网站的及结合自己的想法写这篇文 ...
- .net 框架
目录 API 应用框架(Application Frameworks) 应用模板(Application Templates) 人工智能(Artificial Intelligence) 程序集处理( ...
- robotframework的学习笔记(十六)----robotframework标准库String
官方文档:http://robotframework.org/robotframework/latest/libraries/String.html Introduction A test libra ...
- springmvc注入类 NoUniqueBeanDefinitionException: No qualifying bean of type [] is defined: expected single错误
在springmvc中注入服务时用@Service 当有两个实现类时都标明@Service后则会出现异常: nested exception is org.springframework.beans. ...