Java并发编程原理与实战二十二:Condition的使用
Condition的使用
Condition用于实现条件锁,可以唤醒指定的阻塞线程。下面来实现一个多线程顺序打印a,b,c的例子。
先来看用wait和notify的实现:
public class Demo {
private volatile int singal;
public synchronized void a() {
while (singal != 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("a");
singal++;
notifyAll();
}
public synchronized void b() {
while (singal != 1) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("b");
singal++;
notifyAll();
}
public synchronized void c() {
while (singal != 2) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("c");
singal = 0;
notifyAll();
}
public static void main(String[] args) {
Demo demo = new Demo();
A a = new A(demo);
B b = new B(demo);
C c = new C(demo);
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();
}
}
class A implements Runnable {
private Demo demo;
public A(Demo demo) {
this.demo = demo;
}
@Override
public void run() {
while (true) {
demo.a();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class B implements Runnable {
private Demo demo;
public B(Demo demo) {
this.demo = demo;
}
@Override
public void run() {
while (true) {
demo.b();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class C implements Runnable {
private Demo demo;
public C(Demo demo) {
this.demo = demo;
}
@Override
public void run() {
while (true) {
demo.c();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
再来看一下用Condition的实现,可以发现Condition实现更方便,可以实现指定条件的唤醒:
public class DemoCondition {
private volatile int singal;
private Lock lock = new ReentrantLock();
private Condition a = lock.newCondition();
private Condition b = lock.newCondition();
private Condition c = lock.newCondition();
public void a() {
lock.lock();
while (singal != 0) {
try {
a.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("a");
singal++;
b.signal();
lock.unlock();
}
public void b() {
lock.lock();
while (singal != 1) {
try {
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("b");
c.signal();
singal++;
lock.unlock();
}
public void c() {
lock.lock();
while (singal != 2) {
try {
c.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("c");
a.signal();
singal = 0;
lock.unlock();
}
public static void main(String[] args) {
DemoCondition demo = new DemoCondition();
A a = new A(demo);
B b = new B(demo);
C c = new C(demo);
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();
}
}
class A implements Runnable {
private DemoCondition demo;
public A(DemoCondition demo) {
this.demo = demo;
}
@Override
public void run() {
while (true) {
demo.a();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class B implements Runnable {
private DemoCondition demo;
public B(DemoCondition demo) {
this.demo = demo;
}
@Override
public void run() {
while (true) {
demo.b();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class C implements Runnable {
private DemoCondition demo;
public C(DemoCondition demo) {
this.demo = demo;
}
@Override
public void run() {
while (true) {
demo.c();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.用Condition实现一个有界队列。
public class MyQueue<E> {
private Object[] obj;
// 添加操作下标
private int addIndex;
// 删除操作下标
private int removeIndex;
// 实际队列长度
private int queueSize;
private Lock lock = new ReentrantLock();
private Condition add = lock.newCondition();
private Condition remove = lock.newCondition();
public MyQueue(int count) {
this.obj = new Object[count];
}
public void add(E e) {
lock.lock();
// 队列已满则等待
while (queueSize == obj.length) {
try {
System.out.println(Thread.currentThread().getName() + " 队列已满,不能入队");
add.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
obj[addIndex++] = e;
if (addIndex == obj.length - 1) {
addIndex = 0;
}
queueSize++;
System.out.println(Thread.currentThread().getName() + " 当前队列大小: " + queueSize);
remove.signal();
lock.unlock();
}
public void remove() {
lock.lock();
// 队列已空则等待
while (queueSize == 0) {
try {
System.out.println(Thread.currentThread().getName() + " 队列已空,无法出队");
remove.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
obj[removeIndex] = null;
if (++removeIndex == obj.length) {
removeIndex = 0;
}
queueSize--;
System.out.println(Thread.currentThread().getName() + " 当前队列长度: " + queueSize);
add.signal();
lock.unlock();
}
public static void main(String[] args) {
final MyQueue<Integer> myQueue = new MyQueue<>(4);
new Thread() {
@Override
public void run() {
while (true) {
myQueue.add(1);
}
}
}.start();
new Thread() {
@Override
public void run() {
myQueue.remove();
}
}.start();
}
}
参考资料:
《java并发编程实战》 龙果学院
Java并发编程原理与实战二十二:Condition的使用的更多相关文章
- Java并发编程原理与实战四十二:锁与volatile的内存语义
锁与volatile的内存语义 1.锁的内存语义 2.volatile内存语义 3.synchronized内存语义 4.Lock与synchronized的区别 5.ReentrantLock源码实 ...
- Java并发编程原理与实战三十二:ForkJoin框架详解
1.Fork/Join框架有什么用呢? ------->Fork使用来切分任务,Join是用来汇总结果.举个简单的栗子:任务是1+2+3+...+100这个任务(当然这个任务的结果有好的算法去做 ...
- Java并发编程原理与实战三十五:并发容器ConcurrentLinkedQueue原理与使用
一.简介 一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素进行排序.队列的头部 是队列中时间最长的元素.队列的尾部 是队列中时间最短的元素.新的元素插入到队列的尾部,队列 ...
- Java并发编程原理与实战三十四:并发容器CopyOnWriteArrayList原理与使用
1.ArrayList的实现原理是怎样的呢? ------>例如:ArrayList本质是实现了一个可变长度的数组. 假如这个数组的长度为10,调用add方法的时候,下标会移动到下一位,当移动到 ...
- Java并发编程原理与实战三十六:阻塞队列&消息队列
一.阻塞队列 1.阻塞队列BlockingQueue ---->可以理解成生产者消费者的模式---->消费者要等待到生产者生产出来产品.---->而非阻塞队列ConcurrentLi ...
- Java并发编程原理与实战四十:JDK8新增LongAdder详解
传统的原子锁AtomicLong/AtomicInt虽然也可以处理大量并发情况下的计数器,但是由于使用了自旋等待,当存在大量竞争时,会存在大量自旋等待,而导致CPU浪费,而有效计算很少,降低了计算效率 ...
- Java并发编程原理与实战四十五:问题定位总结
背景 “线下没问题的”. “代码不可能有问题 是系统原因”.“能在线上远程debug么” 线上问题不同于开发期间的bug,与运行时环境.压力.并发情况.具体的业务相关.对于线上的问题利用线上 ...
- Java并发编程原理与实战四十四:final域的内存语义
一.final域的重排序规则 对于final域,编译器和处理器要遵循两个重拍序规则: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 ...
- Java并发编程原理与实战三十八:多线程调度器(ScheduledThreadPoolExecutor)
在前面介绍了java的多线程的基本原理信息:线程池的原理与使用 本文对这个java本身的线程池的调度器做一个简单扩展,如果还没读过上一篇文章,建议读一下,因为这是调度器的核心组件部分. 我们如果要用j ...
- Java并发编程原理与实战三十:CountDownLatch与CyclicBarrier 区别
相信每个想深入了解多线程开发的Java开发者都会遇到CountDownLatch和CyclicBarrier,大家也在网上看到各种介绍原理,代码的,以及他们区别(应付面试)的,但是很少能讲清楚:他们到 ...
随机推荐
- Beta 冲刺 (6/7)
队名:Boy Next Door 燃尽图 代码写入 https://github.com/mangoqiqi/paybook/tree/master/Desktop/Web%E8%B4%A6%E5%8 ...
- qq飞车精灵家园里的背景音乐:Mysterious Town pooka 下载
一直都觉得Mysterious Town pooka特别好听,但是酷狗音乐和网上直接搜搜不到,于是我直接从源文件中找了出来.虽然是.ogg格式,但是在酷狗音乐里还是可以播放的.貌似是<奥丁领 ...
- [转帖]nvidia nvlink互联与nvswitch介绍
nvidia nvlink互联与nvswitch介绍 https://www.chiphell.com/thread-1851449-1-1.html 差不多在一个月前在年度gtc会议上,老黄公开了d ...
- Nginx和Apache区别
Nginx VS Apache 相同点: 1.都是HTTP服务器软件 2.功能上都采用模块化结构设计 3.都支持通用的语言接口,如PHP.Perl.Python等 4.支持正向.反向代理.虚拟主机. ...
- 数据库事务的四大特性以及4种事务的隔离级别-以及对应的5种JDBC事务隔离级别
本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指事务 ...
- UVA11248_Frequency Hopping
给一个有向网络,求其1,n两点的最大流量是否不小于C,如果小于,是否可以通过修改一条边的容量使得最大流量不小于C? 首先对于给定的网络,我们可以先跑一遍最大流,然后先看流量是否大于C. 然后保存跑完第 ...
- DPM(Deformable Parts Model)
DPM(Deformable Parts Model) Reference: Object detection with discriminatively trained partbased mode ...
- 题解 P1208 【[USACO1.3]混合牛奶 Mixing Milk】
其实根本没有一楼dalao描述的那么麻烦...... 一楼dalao其实吧,采用了一种纯属模拟的方式. 下面是我的大跃进思想 但是一个个地做减法是不是太慢了?(大跃进思想) 于是我们是不是可以直接进行 ...
- MT【136】一道三次函数的最佳逼近问题
已知函数\(f(x)=-x^3-3x^2+(1+a)x+b(a<0,b\in R)\), 若\(|f(x)|\)在\([-2,0]\)上的最大值为\(M(a,b)\),求\(M(a,b)\)的最 ...
- 【刷题】HDU 3435 A new Graph Game
Problem Description An undirected graph is a graph in which the nodes are connected by undirected ar ...