笔记_并发编程实践_十四

构建自定义的同步工具
1.除了系统提供的类库可以提供阻塞,通过使用语言和类库提供的底层机制:条件队列,显示的condition对象,和AbstractQueuedSynchronizer构建属于自己的synchronizer

2.条件队列:
(1)条件队列可以让一组线程——称作等待集,以某种方式等待相关的条件变为真,条件队列的元素时线程

(2)为了使用对象x中的人一个条件队列的方法,你必须持有对象X的锁,因为“等待机遇状态的条件”机制必须和“维护状态一致性”机制紧密联系在一起
(可见jdk中的wait,或notify方法的这一句话

此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。
抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
”)

(3)你不能使用"轮询和休眠"完成的任何事情,用条件队列也无法完成(条件表达式使得管理状态的依赖性变得更加简单高效)(原有的语义是一样的)

(4)Object.wait()或者其限时版本使得当前线程等待该对象的锁,直到被notify(wait方法会释放锁)

(5)"每次调用wait都会隐式地与特定的条件谓词相关联,当调用特定的条件谓词的wait时,调用者必须已经持有了与条件队列相关的锁,,这个锁必须同时还保护着组成条件谓词的状态变量"

(6)过早地唤醒:
<1>wait的返回并不一定意味着线程正在等待的条件谓词已经变成真了(一条队列肯能存在多个条件谓词)
<2>每次从wait中唤醒后,都必须再次测试条件谓词.
<3>当使用条件等待时(Object.wait或者Cod\ndition.await):
永远设置一个条件谓词—— 一些对象状态的测试,线程执行前必须满足它
永远在wait前测试测试调价你为此.并且从wait中返回后再次测试(条件谓词)
永远在循环中调用wait(因为要循环执行上一条)
确保构成条件谓词的状态变量被锁保护,而这个锁正是与条件队列相关联
当调用wait‘notify或者notifyAll时。要持有与条件队列相关联的锁;而且,在检查条件谓词之后,开始执行被保护逻辑之前不要释放锁
(7)丢失的信号:当一个线程等待的特定条件为真,但是进入等待前检查条件谓词却返回了假。我们就称出现了一个丢失的信号(如线程a通知了一个条件队列,随后线程b在同一个条件队列中等待,则该线程需要被另一个通知唤醒)(所以在一个线程等待之前必须验证条件谓词,获取条件谓词和wiat等代码都被对应的锁保护)
(8)通知
<1>无论在何时,当你在等待一个条件,一定要确保有人会在条件为此变为真时通知你
<2>由于调用wait的线程都持有对应的锁,所以释放的线程在notify后应该尽快释放锁,不然会一直阻塞
<3>注意:由于条件队列中可能存在多个条件谓词,所以使用notify而不是notifyAll可能会导致所有线程丢失信号
只有在满足下述条件后,才能使用notify代替notifAll:
相同的等待着,只有一个条件为此与条件队列相关,每个线程从wait返回后执行相同的逻辑;并且,一进一出,一个队条件变量的通知之多激活一个线程执行(可以使用’条件通知‘方式优化,即是在符合特定条件下才使用notifyall,减少上下文的切换)
(9)入口协议和出口协议:对于每一个依赖于状态的操作以及每一修改了其他状态的操作都为其定义并文档化一个入口协议和出口协议。(入口协议就是操作条件谓词,出口协议就是检查任何被操作改变的状态变量并通知条件队列)

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package TestConditionQueue;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 条件队列的使用
 */
public class Test {

    /**
     * 条件谓词 注意:条件队列中可以存在多个条件谓词,这是每次wait后应该再次验证提交谓词的其中一个原因
     * 条件谓词应该受条件队列对应的锁保护(试想不受保护的情况下,条件谓词可能在wait后代码执行完前被修改)
     */
    public static volatile Boolean condition = Boolean.FALSE;

    /**
     * 充当锁对象 注意条件队列与锁的关系 使用某一对象上的条件队列必须持有该对象的锁
     */
    public static Object lock = new Object();

    public static void test() {
        synchronized (lock) {//调用wait或者notify方法的时候必须获得对应的锁,否则报异常
            while (condition == Boolean.FALSE) {
                try {
                    lock.wait();//等待完后应该再次验证谓词
                } catch (InterruptedException ex) {
                    Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            //doSomething
            condition = Boolean.FALSE;//修改条件谓词时持有锁
        }

    }

    public static void main(String args[]) {
        test();
    }

}

3.显式的Condition对象(正如Lock时广义的内部锁,Condition时广义的内部条件队列)
(1)注意:内部条件队列的wait、notify、notifyAll方法在Condition中对应的是await、signal、signalAll,但是由于Condition也继承自Object,所以它也有wait,notify,notifyAll方法,不能用错
(2)显式锁的Condition可以使用多个,用这种方式实现多个条件队列更高可读性(若分解至符合单一唤醒的条件后使用单一唤醒效率更优)
4.剖析synchronizer
(1)ReentrantLock、semaphore、CoundownLatch、ReentranReadWritetLock、synchronousQUeue、FutureTask等等都是构建在AbstractQueuedSynchronizer

(2)使用abstractQueuedSynchronizer构建的Synchronizer只可能在一个点上发生阻塞,降低了上下文切换的开销,提高了吞吐量。
5.AbstractQueuedSynchronizer
(1)子类应该覆盖tryAcquire,tryAcquireShare(允许共享获取的)和tryRealse、tryRealseShare方法,isHeldExclusively(是否杜赞访问)(子类会更具这些方法确定是否该执行对应操作
(2)AbstractQueuedSynchronizer同样提供了一些机制用于创建条件变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值