JUC——线程同步锁(Condition精准控制)
在进行锁处理的时候还有一个接口:Condition,这个接口可以由用户来自己进行锁的对象创建。
Condition的作用是对锁进行更精确的控制。
Condition的await()方法相当于Object的wait()方法,Condition的signal()方法相当于Object的notify()方法,Condition的signalAll()方法相当于Object的notifyAll()方法。
不同的是Object的wait(), notify(), notifyAll() 方法是和“同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与“互斥锁/共享锁”捆绑使用。
| Object | Condition | |
| 休眠 | wait() | await() |
| 唤醒单个线程 | notify() | signal() |
| 唤醒多个线程 | notifyAll() | signalAll() |

范例:观察Condition的基本使用
package so.strong.mall.concurrent; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class ConditionDemo {
private static String msg = null; //设置一个字符串
public static void main(String[] args) throws Exception{
final Lock myLock = new ReentrantLock(); //实例化Lock接口对象
final Condition condition = myLock.newCondition(); //创建一个新的Condition接口对象
myLock.lock();
//如果现在不进行锁定,那么Condition无法执行等代理处理机制,会出现IllegalMonitorStateException
try {
new Thread(new Runnable() {
@Override
public void run() {
myLock.lock();
try {
msg = "itermis.com";
condition.signal(); //唤醒等待的Condition
} finally {
myLock.unlock();
}
}
}).start();
condition.await(); //线程等待
System.out.println("*******主线程执行完毕,msg="+msg);
} finally {
myLock.unlock(); //解除阻塞状态
}
}
}
//*******主线程执行完毕,msg=itermis.com
与之前的Object相比,唯一的区别在于:现在看不见明确的synchronized关键字,而取代synchronized是Lock接口中的lock(),unlock()两个方法,而后在阻塞状态(同步状态)下可以使用Condition中的await()与signal()方法进行等待与唤醒的操作处理。

范例:实现数据的缓冲控制
package so.strong.mall.concurrent; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; /**
* @author Termis
* @date 2018/5/3
*/
public class DataBufferDemo {
public static void main(String[] args) {
final DataBuffer db = new DataBuffer();
for (int i = 0; i < 3; i++) { //创建3个写线程
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 2; j++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
db.put(Thread.currentThread().getName() + "写入数据,j=" + j);
}
}
}, "生产者-" + i).start();
} for (int i = 0; i < 5; i++) { //创建5个读线程
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("[(" + Thread.currentThread().getName() + ")CONSUMER]" + db.get());
}
}
}, "消费者-" + i).start();
}
}
} class DataBuffer { //进行数据的缓冲操作控制
private static final int MAX_LENGTH = 5; // 该类之中保存的数组长度的个数为5
private Object[] data = new Object[MAX_LENGTH]; //定义一个数组进行全部数据的保存控制
private Lock myLock = new ReentrantLock(); //创建数据锁
private Condition putCondition = myLock.newCondition(); //数据保存的Condition控制
private Condition getCondition = myLock.newCondition(); //数据读取的Condition控制
private int putIndex = 0; //写入数据的索引
private int getIndex = 0; //读取数据的索引
private int count = 0; //当前保存的元素个数 public Object get() {
Object getObj = null;
this.myLock.lock();
try {
if (this.count == 0) //没有写入
this.getCondition.await(); //读取的线程要进行等待
getObj = this.data[this.getIndex++]; //读取指定索引数据
if (this.getIndex == MAX_LENGTH)
this.getIndex = 0; //重新开始读
this.count--; //因为读了一个数据之后,现在需要减少个数
this.putCondition.signal(); //告诉写线程可以写入
} catch (Exception e) {
e.printStackTrace();
} finally {
this.myLock.unlock();
}
return getObj;
} public void put(Object obj) { //进行缓冲数据的写入操作
this.myLock.lock(); //进入独占锁状态
try {
if (this.count == MAX_LENGTH) //保存的数据已经满了
this.putCondition.await(); //暂时先别进行数据保存了
this.data[this.putIndex++] = obj; //保存当前数据
if (this.putIndex == MAX_LENGTH) //现在索引已经写满
this.putIndex = 0; //重置数组操作的索引脚标
this.count++; //保存的个数需要做一个追加
this.getCondition.signal(); //唤醒消费线程
System.out.println("[(" + Thread.currentThread().getName() + ")写入缓冲-put()]" + obj);
} catch (Exception e) {
e.printStackTrace();
} finally {
this.myLock.unlock(); //不管如何最终一定要进行解锁
}
}
}
[(生产者-2)写入缓冲-put()]生产者-2写入数据,j=0
[(生产者-1)写入缓冲-put()]生产者-1写入数据,j=0
[(生产者-0)写入缓冲-put()]生产者-0写入数据,j=0
[(生产者-1)写入缓冲-put()]生产者-1写入数据,j=1
[(生产者-2)写入缓冲-put()]生产者-2写入数据,j=1
[(消费者-3)CONSUMER]生产者-2写入数据,j=0
[(消费者-4)CONSUMER]生产者-1写入数据,j=1
[(消费者-1)CONSUMER]生产者-0写入数据,j=0
[(消费者-2)CONSUMER]生产者-1写入数据,j=0
[(生产者-0)写入缓冲-put()]生产者-0写入数据,j=1
[(消费者-0)CONSUMER]生产者-2写入数据,j=1
[(消费者-3)CONSUMER]生产者-0写入数据,j=1
对于生产者和消费者模型的实现,除了多线程基础实现之外,也可以采用以上的模式利用Lock与Condition进行精确控制。
JUC——线程同步锁(Condition精准控制)的更多相关文章
- JUC——线程同步锁(锁处理机制简介)
锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...
- JUC——线程同步锁(ReentrantReadWriteLock读写锁)
读写锁简介 所谓的读写锁值得是两把锁,在进行数据写入的时候有一个把“写锁”,而在进行数据读取的时候有一把“读锁”. 写锁会实现线程安全同步处理操作,而读锁可以被多个对象读取获取. 读写锁:ReadWr ...
- JUC——线程同步锁(LockSupport阻塞原语)
java.util.concurrent.locks.LockSupport这个是一个独立的类,这个类的主要功能是用来解决Thread里面提供的suspend()(挂起线程).resume()(恢复运 ...
- JUC——线程同步锁(ReentrantLock)
ReentrantLock简介 ReentrantLock是一个可重复的互斥锁,又被称为独占锁,可重入的意思是:ReentrantLock锁可以被单个线程多次获取.但是在同一个时间点只能被一个线程锁持 ...
- Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量
在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...
- 多线程 - 线程同步锁(lock、Monitor)
1. 前言 多线程编程的时候,我们不光希望两个线程间能够实现逻辑上的先后顺序运行,还希望两个不相关的线程在访问同一个资源的时候,同时只能有一个线程对资源进行操作,否则就会出现无法预知的结果. 比如,有 ...
- Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- Python3 进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- Java线程同步锁
把synchronized当作函数修饰符时,示例代码如下: Public synchronized void method(){ //-. } 这也就是同步方法,那这时synchronized锁定的是 ...
随机推荐
- MapReduce实例&YARN框架
MapReduce实例&YARN框架 一个wordcount程序 统计一个相当大的数据文件中,每个单词出现的个数. 一.分析map和reduce的工作 map: 切分单词 遍历单词数据输出 r ...
- jQuery实现简易轮播图的效果
(图片素材取自于小米官网) 刚开始接触jQuery的学习,个人觉得如果为了实现多数的动态效果,jQuery的确很简易方便. 下面简易的轮播图效果,还请前辈多多指教~ (努力学习react vue an ...
- debian 7 linux 安装jdk出现Error occurred during initialization of VM java/lang/NoClassDefFoun
debian 7 linux 安装jdk出现Error occurred during initialization of VM java/lang/NoClassDefFoun 这两天一直研究lin ...
- 嵌套的ng-repeat双层循环,内层如何获取外层的$index?
html代码: <div> <ul ng-repeat="row in table track by $index"> <li ng-repeat=& ...
- nginx配置解析之客户端真实IP的传递
前后端分离之后,采用nginx作为静态服务器,并通过反向代理的方式实现接口跨域的方式,在降低开发成本的同时也带来了诸多问题,例如客户端真实IP的获取. 在一些特殊场景下,比如风控和支付流程,往往需要获 ...
- BZOJ1434:[ZJOI2009]染色游戏(博弈论)
Description 一共n×m个硬币,摆成n×m的长方形.dongdong和xixi玩一个游戏,每次可以选择一个连通块,并把其中的硬币全部翻转,但是需要满足存在一个硬币属于这个连通块并且所有其他硬 ...
- 【2015蓝桥杯省赛】C++ B组试题
1.奖券数目 作答:52488,正确 #include <iostream> using namespace std; bool check(int x) { ] = { }; while ...
- [Java123] JavaBean
https://stackoverflow.com/questions/3295496/what-is-a-javabean-exactly A JavaBean is just a standard ...
- python基础整理4——面向对象装饰器惰性器及高级模块
面向对象编程 面向过程:根据业务逻辑从上到下写代码 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程 面向对象编程(Object Oriented Pro ...
- sql三表查询
情景: student id stname sex score scoreid stname birth course id coursename age 简单说明 a ...