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

《Java并发编程实战》第十四章 构建自己定义的同步工具 读书笔记

2016-01-30 20:11 471 查看

一、状态依赖性的管理

有界缓存实现的基类

@ ThreadSafe
public abstract class BaseBoundedBuffer<E> {
@GuardeBy( "this" ) private final E[] buf;
@GuardeBy( "this" ) private int tail;
@GuardeBy( "this" ) private int head;
@GuardeBy( "this" ) private int count;

protected BaseBoundedBuffer( int capacity) {
this .buf = (E[]) new Object[capacity];
}

protected synchronized final void doPut(E E) {
buf[tail] = E;
if (++tail == buf.length) {
tail = 0;
}
++count;
}

protected synchronized final E doTake() {
E E = buf[head];
buf[head] = null ;
if (++head == buf.length) {
head = 0;
}
--count;
return E;
}

public synchronized final boolean isFull() {
return count == buf.length;
}

public synchronized final boolean isEmpty() {
return count == 0;
}
}


1 演示样例:将前提条件的失败传递给调用者

@ ThreadSafe
public class GrumpyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
public GrumpyBoundedBuffer( int size){
super (size);
}

public synchronized void put(V v){
if (isFull()){
throw new BufferFullException ();
}
doPut(v);
}

public synchronized V take(){
if (isEmpty())
throw new BufferEmptyExeption ();
return doTake();
}
}


缓存为空或者已满都不是异常情况,使用者必需要捕获这些异常才干进行正确的处理。

while (true ){
try {
V item = buffer.take();
// 对于item运行一些操作
break ;
} catch (BufferEmptyException e) {
Thread. sleep(SLEEP_GRANULARITY );
}
}


2 演示样例:通过轮询与休眠来实现简单的堵塞
从上面的代码能够看出。堵塞与出现异常都须要方法的使用者来处理,如今尝试都封装到有界缓存中。

@ ThreadSafe
public class SleepyBoundedBuffer<V> extends BaseBoundedBuffer<V> {
public SleepyBoundedBuffer( int size) {
super (size);
}

public void put(V v) throws InterruptedException{
while (true ){
synchronized (this ){
if (!isFull()){
doPut(v);
return ;
}
}
Thread.sleep(SLEEP_GRANULARITY);
}
}

public V take() throws InterruptedException{
while (true ){
synchronized (this ){
if (!isEmpty()){
return doTake();
}
}
Thread.sleep(SLEEP_GRANULARITY);
}
}
}


3 条件队列
不须要使用while(true),改为使用wait、notifyAll

@ ThreadSafe
public class BoundedBuffer<V> extends BaseBoundedBuffer<V> {

// 条件谓词:not-full (!isFull())
// 条件谓词:not-empty (!isEmpty())

public BoundedBuffer( int size) {
super (size);
}

// 堵塞并直道:not-full
public synchronized void put(V v) throws InterruptedException{
while (isFull()){
wait();
}
doPut(v);
notifyAll();
}

// 堵塞并直道:not-empty
public synchronized V take() throws InterruptedException{
while (isEmpty()){
wait();
}
V v = doTake();
notifyAll();
return v;
}
}


二、使用条件队列

1 条件谓词
要想正确地使用条件队列,关键是找出对象在哪个条件谓词上等待。

2 过早唤醒
比如:内置条件队列中有多个条件谓语。此时假设调用notifyAll其含义是通知全部wait,可是并不一定全部条件谓语都满足运行条件。

当使用条件等待时(比如Object.wait或Condition.await):

. 通常都有一个条件谓词--包含一些对象状态的測试,线程在运行前必须首先通过这些測试。

. 在调用wait之前測试条件谓词,而且从wait中返回时再次进行測试。

. 在一个循环中调用wait。

. 确保使用与条件队列相关的锁来保护构成条件谓词的各个状态变量。

. 当调用wait、notify或notifyAll等方法时。一定要持有与条件队列相关的锁。

. 在检查条件谓词之后以及開始运行对应的操作之前。不要释放锁。

3 丢失的信号
已经满足通知的条件发出通知,可是之后才进入堵塞wait状态。所以wait永远等不到在其前面发出的notify。

4 通知

5 演示样例:阀门类

6 子类的安全问题

7 封装条件队列

8 入口协议与出口协议

三、显式的Condition对象

四、Synchronizer剖析

五、AbstractQueuedSynchronizer

六、java.util.concurrent同步器类中的 AQS

1 ReentrantLock

2 Semaphore与CountDownLatch

3 FutureTask

4 ReentrantReadWriteLock
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: