您的位置:首页 > 编程语言 > Java开发

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 编程 并发 线程