第五章 基础构建模块
摘要: 本章主要介绍了Java中几个比较重要的开发模块。
1. 同步容器类 Vector HashTable
同步容器虽然是线程安全的容器,但是在执行某些操作的时候可能会抛出异常,这并不是我们想要的。例如Vector的getLast和deleteLast两个操作在两个线程中交替运行时,就有可能抛出ArrayIndexOutOfBoundsException。还有一个隐藏的问题就是这类容器在设计的时候无论是fail-fast还是迭代不使用锁都可能与我们编程想要的结果是不一致的。
2. 并发容器 ConcurrentHashMap CopyOnWriteArrayList
书中推荐大家更多的使用并发容器而尽量减少使用同步容器,因为并发容器使用内部锁来实现同步,也就是说是使用了粒度更小的锁,这样可以在高并发的情况下实现更高的吞吐量而且在单线程环境中只损失非常小的性能。另外他使用的迭代器是弱一致性的,他可以容忍并发修改。不过这也有缺点就是不是精确的,例如size和isEmpty他的值可能是失效数据。
3. 阻塞队列与生产者-消费者模式
阻塞队列提供了put和take以及支持定时的offer和poll方法。BlockingQueue简化了生产者-消费者场景,在Java的线程池Executor中就使用了生产者-消费者模式当做基本架构的概念。
Deque和BlockingDeque是双端队列,单端队列对应生产者-消费者模式,而双端队列则对应工作密取。
工作密取: 多个消费者维护多个双端队列,当消费者A完成了自己队列中的所有工作后,他就可以去其他消费者的双端队列的末端秘密的取一个。他会在垃圾回收对堆进行标记时使用到。
4. 同步工具
这一节主要介绍了 CountDownLatch、FutureTask、semaphore、CyclicBarrier相关的特点和应用。这里我就不做过多的介绍了。
5. 高效缓存的实现方式
public class Memoizer3 <A, V> implements Computable<A, V> {
private final Map<A, Future<V>> cache
= new ConcurrentHashMap<A, Future<V>>();
private final Computable<A, V> c;
public Memoizer3(Computable<A, V> c) {
this.c = c;
}
public V compute(final A arg) throws InterruptedException {
Future<V> f = cache.get(arg);
if (f == null) {
Callable<V> eval = new Callable<V>() {
public V call() throws InterruptedException {
return c.compute(arg);
}
};
FutureTask<V> ft = new FutureTask<V>(eval);
f = ft;
cache.put(arg, ft);
ft.run(); // call to c.compute happens here
}
try {
return f.get();
} catch (ExecutionException e) {
throw LaunderThrowable.launderThrowable(e.getCause());
}
}
}