在进行锁处理的时候还有一个接口:Condition,这个接口可以由用户来自己进行锁的对象创建。

  Condition的作用是对锁进行更精确的控制。

  Conditionawait()方法相当于Objectwait()方法,Conditionsignal()方法相当于Objectnotify()方法,ConditionsignalAll()方法相当于ObjectnotifyAll()方法。

  不同的是Objectwait(), 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关键字,而取代synchronizedLock接口中的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

  对于生产者和消费者模型的实现,除了多线程基础实现之外,也可以采用以上的模式利用LockCondition进行精确控制。

JUC——线程同步锁(Condition精准控制)的更多相关文章

  1. JUC——线程同步锁(锁处理机制简介)

    锁处理机制简介 juc的开发框架解决的核心问题是并发访问和数据安全操作问题,当进行并发访问的时候如果对于锁的控制不当,就会造成死锁这样的阻塞问题. 为了解决这样的缺陷,juc里面重新针对于锁的概念进行 ...

  2. JUC——线程同步锁(ReentrantReadWriteLock读写锁)

    读写锁简介 所谓的读写锁值得是两把锁,在进行数据写入的时候有一个把“写锁”,而在进行数据读取的时候有一把“读锁”. 写锁会实现线程安全同步处理操作,而读锁可以被多个对象读取获取. 读写锁:ReadWr ...

  3. JUC——线程同步锁(LockSupport阻塞原语)

    java.util.concurrent.locks.LockSupport这个是一个独立的类,这个类的主要功能是用来解决Thread里面提供的suspend()(挂起线程).resume()(恢复运 ...

  4. JUC——线程同步锁(ReentrantLock)

    ReentrantLock简介 ReentrantLock是一个可重复的互斥锁,又被称为独占锁,可重入的意思是:ReentrantLock锁可以被单个线程多次获取.但是在同一个时间点只能被一个线程锁持 ...

  5. Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量

    在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...

  6. 多线程 - 线程同步锁(lock、Monitor)

    1. 前言 多线程编程的时候,我们不光希望两个线程间能够实现逻辑上的先后顺序运行,还希望两个不相关的线程在访问同一个资源的时候,同时只能有一个线程对资源进行操作,否则就会出现无法预知的结果. 比如,有 ...

  7. Python并发编程-进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  8. Python3 进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  9. Java线程同步锁

    把synchronized当作函数修饰符时,示例代码如下: Public synchronized void method(){ //-. } 这也就是同步方法,那这时synchronized锁定的是 ...

随机推荐

  1. 个人作业2——集大通APP案例分析

    个人作业2——集大通APP案例分析 产品:集大通 我认为这个是我们学校的APP,我们应该支持一下. 一.个人体验 1.下载并使用,描述最简单直观的个人第一次上手体验. ①界面美观,可以感受到丰富的校园 ...

  2. Windows 7防火墙阻止了远程桌面连接的解决方法

    在[系统属性]中已经设置了允许远程桌面连接了,但是还是不能远程桌面的话,很可能是你的windows防火墙处于“启用”状态,防火墙阻止了windows 7系统的远程桌面连接.你可以使用以下的方法检查解决 ...

  3. Perl之my与local

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/sunshoupo211/article/details/31745909    在函数定义中,使用m ...

  4. UVa 1252 - Twenty Questions(状压DP)

    链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  5. 3226. [SDOI2008]校门外的区间【线段树】

    Description   受校门外的树这道经典问题的启发,A君根据基本的离散数学的知识,抽象出5种运算维护集合S(S初始为空)并最终输出S.现在,请你完成这道校门外的树之难度增强版——校门外的区间. ...

  6. 如何搭建github+hexo博客-转

    1.前言 其实早在这之前我就一直想过写博客,但由于种种原因一直没有去学习这方面的知识,最近半个月(从开始动手到搭建好)一直陆陆续续的在着手这方面的工作.从开始到搭建完成的过程中遇到了很多困难,因为在这 ...

  7. javascript:apply方法 以及和call的区别 (转载)

    javascript:apply方法   1.        apply和call的区别在哪里 2.        什么情况下用apply,什么情况下用call 3.        apply的其他巧 ...

  8. python range函数与numpy arange函数,xrange与range的区别

    转自:https://www.cnblogs.com/ymjyqsx/p/6426764.html 1.range()返回的是range object,而np.arange()返回的是numpy.nd ...

  9. mac 设置mysql开机自启动

    1.编辑一个mysql启动文件. 在终端里面输入: sudo vi /Library/LaunchDaemons/com.mysql.mysql.plist 2.输入启动文件内容: <?xml ...

  10. MongoDB DBA 实践1-----Windows

    一.先决条件 1.支持的平台 在3.4版中更改: MongoDB不再支持32位x86平台. MongoDB需要x86-64架构并支持以下内容: Windows 7 / Server 2008 R2 W ...