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锁定的是 ...
随机推荐
- PHP设计模式系列 - 委托模式
委托模式 通过分配或委托其他对象,委托设计模式能够去除核心对象中的判决和复杂的功能性. 应用场景 设计了一个cd类,类中有mp3播放模式,和mp4播放模式 改进前,使用cd类的播放模式,需要在实例化的 ...
- jquery validation验证身份证号、护照、电话号码、email
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 【cs231n】图像分类 k-Nearest Neighbor Classifier(K最近邻分类器)【python3实现】
[学习自CS231n课程] 转载请注明出处:http://www.cnblogs.com/GraceSkyer/p/8763616.html k-Nearest Neighbor(KNN)分类器 与其 ...
- python第二十五课——闭包
满足闭包的三个条件: 1).有外部函数和内部函数这样的结构 2).外部函数中定义的变量被内部函数所使用 3).内部函数对象作为返回值被外部函数返回 演示闭包的定义和使用: def outer(): a ...
- PHPExcel 导入
首先: //包含excel的类库require APPPATH . 'third_party/PHPExcel.php';require APPPATH . 'third_party/PHPExcel ...
- chrome://命令
一些常用的命令: chrome://version 显示当前版本 chrome://flags 实验项目,加“#项目名称”锚点可以直接定位到项目 chrome://settings 设置,下图是设置定 ...
- java读入和输出
一: 在python里直接使用input函数就可以,在java里,需要使用Scanner类,用System.in进行初始化,获取用户输入可以用nextLine获取字符串,nextInt获取整形数据. ...
- the django travel three[form表单验证]
一:表单验证: 场景:因为浏览器的js可以被禁用,所以需要做后台的输入合法的验证. A:ajax发请求.需要注意的是ajax POST的数据的key值和form表单的里的字段名字一致,否则得不到验证! ...
- webStorm常用设置之过滤文件夹
webStorm是一款很好用的前端IDE,但是不能否认的是webStorm很重,没有sublime轻便 尤其是项目cnpm后,加载node_modules时的状态,简直想那块豆腐自杀有莫有,就算你耐心 ...
- DL4NLP —— 序列标注:BiLSTM-CRF模型做基于字的中文命名实体识别
三个月之前 NLP 课程结课,我们做的是命名实体识别的实验.在MSRA的简体中文NER语料(我是从这里下载的,非官方出品,可能不是SIGHAN 2006 Bakeoff-3评测所使用的原版语料)上训练 ...