在进行锁处理的时候还有一个接口: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精准控制)的更多相关文章

  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. 装office系统软件

    在电脑里搜索 SW_DVD5_Office_Professional_Plus_2010w_SP1_64Bit_ChnSimp_CORE_MLF_X17-76742 如果已经安装过了,有错误,直接进行 ...

  2. Type Safety and Type Inference

    Swift is a type-safe language. A type safe language encourages you to be clear about the types of va ...

  3. k8s存储 pv pvc ,storageclass

    1.  pv  pvc 现在测试 glusterfs  nfs  可读可写, 多个pod绑定到同一个pvc上,可读可写. 2. storageclass  分成两种 (1)  建立pvc, 相当于多个 ...

  4. linq to sql 中增删改查

    首先我先说一下,如果真的要用linq做项目的话,也会是比较方便的.已经尝试了在三层架构中应用linq to sql 比较方便. //有三个不同的数据库表,所以写法不一样 public class Li ...

  5. etherlime-1-Quick Start

    https://etherlime.readthedocs.io/en/latest/getting-started.html Quick Start Installing全局安装 npm i -g ...

  6. 模糊控制——(3)模糊自适应整定PID控制

    1.原理 这种控制必须精确地确定对象模型,首先将操作人员(专家)长期实践积累的经验知识用控制规则模型化,然后运用推理便可对PID参数实现最佳调整. 自适应模糊PID控制器以误差e和误差变化ec作为输入 ...

  7. JDBC 使用common-dbutiles

    一:第三方jar mysql-connector-java-5.1.45-bin.jar,需要关注的核心类: 1.DbUtils----操作数据库的连接注册和释放. 2:.QueryRunner--- ...

  8. P1006 传纸条

    题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了.幸运的是 ...

  9. Windows Mysql8 设置大小写敏感

    windows系统无法改成 lower_case_table_names=0, 因为windows默认是1,就算改也只能改成2,以下截自 MySQL 8.0 Reference Manual 然后,当 ...

  10. Android TV 全屏无标题

    想要全部窗口全屏无标题,修改 res\values\styles.xml 可设置主题和样式 <resources> <!-- Base application theme, depe ...