java并发编程:自定义同步工具

来源:互联网 发布:龙珠直播软件 编辑:程序博客网 时间:2024/06/05 22:37

条件谓词

在进行某些操作之前,需要进行一些先置条件判断。例如阻塞队列BlockingQueue在进行put操作之前,要先判断队列是否已满,如果已满,就会阻塞,直到队列空出位置出来,才能释放出来,继续执行操作。其中,“队列是否已满”就是条件谓词。

条件队列

在操作不满足条件谓词时,就会被阻塞,该线程就会被塞入对应锁的等待队列中,这个队列即为条件队列。

使用notify的危害

队列中如果有多种条件谓词,可能出现当条件谓词A满足条件后,打算唤醒线程A,但是由于notify的随机唤醒机制,却唤醒了条件谓词为B的线程B,导致线程A一直等不到唤醒信号,线程B被唤醒了,但是它的条件谓词却不为真。

使用notify的优点

notify比notifyAll高效。notifyAll是把所有等待的线程全部唤醒,这些线程会发生竞争,等到其中一个线程获取到锁之后,其它大部分线程就又会回到休眠状态。这过程中,将会出现大量的线程竞争和线程上下文切换。

使用notify的条件

  1. 条件队列中,只有一种条件谓词
  2. 条件队列为单进单出队列

信号丢失问题

  1. 使用notify可能引起信号丢失
  2. 条件谓词为真,线程被唤醒之后,条件谓词却又被其它线程修改为假了

信号丢失问题解决办法

  1. 尽量不使用notify,要使用的话,一定要满足上述使用notify的所有条件
  2. 在线程被唤醒之后,对条件谓词进行再次判断,如果不为真,则继续等待

使用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。

阅读全文
1 0
原创粉丝点击