java并发编程:自定义同步工具
2017-05-17 17:24
387 查看
条件谓词
在进行某些操作之前,需要进行一些先置条件判断。例如阻塞队列BlockingQueue在进行put操作之前,要先判断队列是否已满,如果已满,就会阻塞,直到队列空出位置出来,才能释放出来,继续执行操作。其中,“队列是否已满”就是条件谓词。条件队列
在操作不满足条件谓词时,就会被阻塞,该线程就会被塞入对应锁的等待队列中,这个队列即为条件队列。使用notify的危害
队列中如果有多种条件谓词,可能出现当条件谓词A满足条件后,打算唤醒线程A,但是由于notify的随机唤醒机制,却唤醒了条件谓词为B的线程B,导致线程A一直等不到唤醒信号,线程B被唤醒了,但是它的条件谓词却不为真。使用notify的优点
notify比notifyAll高效。notifyAll是把所有等待的线程全部唤醒,这些线程会发生竞争,等到其中一个线程获取到锁之后,其它大部分线程就又会回到休眠状态。这过程中,将会出现大量的线程竞争和线程上下文切换。使用notify的条件
条件队列中,只有一种条件谓词条件队列为单进单出队列
信号丢失问题
使用notify可能引起信号丢失条件谓词为真,线程被唤醒之后,条件谓词却又被其它线程修改为假了
信号丢失问题解决办法
尽量不使用notify,要使用的话,一定要满足上述使用notify的所有条件在线程被唤醒之后,对条件谓词进行再次判断,如果不为真,则继续等待
使用object自带的方法创建同步工具
我们这里用object自带的方法来实现阻塞队列。public class BlockingQueueUseObject { private Object[] array = new Object[10]; private int count = 0; public synchronized void put(Object obj) throws InterruptedException { while (count == array.length) { this.wait(); } array[count] = obj; count++; if (count == 1) { this.notifyAll(); } } public synchronized Object take() throws InterruptedException { while (count == 0) { this.wait(); } count--; if (count == array.length - 1) { this.notifyAll(); } return array[count]; } }
使用显示的Condition对象
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class BlockingQueueUseObject { private ReentrantLock lock = new ReentrantLock(); private Condition notFull = lock.newCondition(); private Condition notEmpty = lock.newCondition(); private Object[] array = new Object[10]; private int count = 0; public synchronized void put(Object obj) throws InterruptedException { lock.lock(); try { while (count == array.length) { notFull.await(); } array[count] = obj; count++; if (count == 1) { notEmpty.signal(); } } finally { lock.unlock(); } } public synchronized Object take() throws InterruptedException { lock.lock(); try { while (count == 0) { notEmpty.await(); } count--; if (count == array.length - 1) { notFull.signal(); } return array[count]; } finally { lock.unlock(); } } }
使用Condition的优点
每个条件队列都与锁绑定,JVM内置锁只能绑定一个条件队列,如果有多个条件谓词的时候,只能使用notifyAll,比较低效。而显示锁ReentrantLock可以创建多个Condition,每个Condition自带一个条件队列,能够使用比较高效的signal。相关文章推荐
- Java多线程并发编程之构建自定义同步工具
- 并发编程实战学习笔记(十)-构建自定义的同步工具
- 并发编程10.构建自定义的同步工具
- (35)21.3.6 在其它对象上同步---Java编程思想之并发笔记
- Java并发编程4.5-同步策略的文档化
- 【Java并发编程】:图文讲述同步的另一个重要功能:内存可见性
- Java并发编程-13-在集合点的同步-CyclicBarrier
- 【Java并发编程实战】—– AQS(四):CLH同步队列
- Java并发编程之同步互斥问题
- Java并发编程-同步(六)
- 【Java并发编程】之十四:图文讲述同步的另一个重要功能:内存可见性
- [Java Concurrency in Practice]第十四章 构建自定义的同步工具
- Java并发编程:同步容器
- Java并发编程类学习五(同步工具)
- Java并发编程之同步互斥问题
- 【Java并发编程】之十四:图文讲述同步的另一个重要功能:内存可见性
- java 并发编程实战第三章同步辅助类CyclicBarrier解析
- java并发编程实战手册第三章同步辅助类Phaser
- Java并发和多线程4:使用通用同步工具CountDownLatch实现线程等待
- 【Java并发编程实战】----- AQS(四):CLH同步队列