Java并发编程实战
来源:互联网 发布:主机域名是什么 编辑:程序博客网 时间:2024/05/22 03:14
如何创建线程安全的状态依赖的类?
状态依赖操作如一直阻塞直到某个条件为真。
四种实现方法:
方法一:在类库中现有状态依赖类的基础上进行构造
如利用BlockingQueue, FutureTask, CountdownLatch, Semaphore 等构建状态依赖的类。这是首选的简单安全的方法。
示例:下面的例子通过CountDownLatch只设值一次,如果没有设值就等待。
public class ValueLatch <T> { private T value = null; private final CountDownLatch done = new CountDownLatch(1); public boolean isSet() { return (done.getCount() == 0); } public synchronized void setValue(T newValue) { if (!isSet()) { value = newValue; done.countDown(); } } public T getValue() throws InterruptedException { done.await(); synchronized (this) { return value; } }}
方法二:内置的条件队列
条件队列:一种等待线程集合能够通过某种方式等待特定条件为真。
每个Java对象既可以作为锁,也可以作为条件队列。
Object的wait, notify, notifyAll 方法构造内部条件队列的API。
条件等待中的三元关系: 锁,wait方法和条件谓词。
条件谓词就是使某个操作称为状态依赖操作的前提条件。如缓存不为空时,take方法才能执行,否则等待。
状态依赖方法的典型模式:
void stateDependentMethod() throws InterruptedException { //通过锁来保护条件谓词 synchronized(lock) { while(!conditionPredicate()) lock.wait(); } }
当使用条件等待时(Object.wait 或 Condition.await):
- 通常都有一个条件谓词对一些对象状态的测试。
- 在调用wait之前测试条件谓词,并且从wait中返回时再次进行测试。
- 在一个循环中调用wait。
- 确保使用与条件谓词相关的锁来保护构成条件谓词的各个状态变量。
- 当调用wait, notify, notifyAll 方法时,一定要持有与条件队列相关的锁。
- 在检查条件谓词之后以及开始执行相应的操作之前,不要释放锁。
大多数情况下使用notifyAll,只有同时符合下面两个条件时才用notify:
1. 所有等待线程的类型都相同。只有一个条件谓词与条件队列相关,并且每个线程在从wait返回后将执行相同的操作。
2. 单进单出。在条件变量的的每次通知,最多只唤醒一个线程来执行。
方法三:显示的Condition对象
内置条件队列有不足,如内置锁只能有一个相关联的条件队列。
Lock和Condition可以使用带有多个条件谓词的并发对象,或对条件队列有更多的控制权,如限时,公平性。
示例:
public class ConditionBoundedBuffer <T> { protected final Lock lock = new ReentrantLock(); // CONDITION PREDICATE: notFull (count < items.length) private final Condition notFull = lock.newCondition(); // CONDITION PREDICATE: notEmpty (count > 0) private final Condition notEmpty = lock.newCondition(); private static final int BUFFER_SIZE = 100; private final T[] items = (T[]) new Object[BUFFER_SIZE]; private int tail, head, count; // BLOCKS-UNTIL: notFull public void put(T x) throws InterruptedException { lock.lock(); try { while (count == items.length) notFull.await(); items[tail] = x; if (++tail == items.length) tail = 0; ++count; notEmpty.signal(); } finally { lock.unlock(); } } // BLOCKS-UNTIL: notEmpty public T take() throws InterruptedException { lock.lock(); try { while (count == 0) notEmpty.await(); T x = items[head]; items[head] = null; if (++head == items.length) head = 0; --count; notFull.signal(); return x; } finally { lock.unlock(); } }}
方法四:AbstractQueuedSynchronizer(AQS)
AQS是一个用于构建锁和同步器的框架。
基于AQS的同步器,只可能在一个时刻发生阻塞,从而降低上下文切换的开销,提供吞吐量和可伸缩性。
在基于AQS的同步器,最基本的操作是获取操作和释放操作。
java.util.concurrent包中很多可阻塞类都是基于AQS,
如 ReentrantLock, Semaphore, CountdownLatch, ReentrantReadWriteLock, SynchronousQueue, FutureTask等。
- Java并发编程实战
- Java并发编程实战--
- Java并发编程实战-
- Java 并发编程实战
- java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- Java并发编程实战
- 欧拉函数学习笔记整理 POJ 2407+POJ 1284+POJ 2478+POJ 3090
- FluentValidation使用案例
- Notification样式
- NoClassDefFoundError: org/slf4j/LoggerFactory和NoClassDefFoundError: org/apache/log4j/LogManager解决方法
- 输出以下图案:菱形
- Java并发编程实战
- JQuery 当当网订单页
- JAVA 10进制转16进制高位在前地位在后
- Tomcat7.0的安装及配置
- redis动态增加内存(不重启)
- 线程间操作无效: 从不是创建控件“”的线程访问它~~~的解决方法~【转】
- OkHttp源码解析2
- AS3.0游戏内嵌网页
- RMQ (Range Minimum/Maximum Query)算法(查询区间最值)