CompletableFuture
CompletableFuture是在Java8中引入的,拥有强大的功能,支持回调、工作流、异常处理等。CompletableFuture还是典型的Java8的工具类,有函数式编程、链式方法和语义化接口等.
除了Future接口,CompletableFuture还实现了CompletionStage接口。这个接口内容丰富,CompletableFuture的工作流功能,就是实现了这个接口。CompletionStage接口描述了任务之间的多种关系,包括:串行关系、并行关系、AND汇聚关系、OR汇聚关系。同时,支持这些关系的组合。
StampedLock
StampedLock是在Java8中引入的,是一种比ReadWriteLock更快的读写锁。因为,StampedLock对场景进行进一步的细分,把读锁分类为悲观读锁与乐观读,ReadWriteLock中的读锁类似于StampedLock的悲观读锁。因此,StampedLock有三种模式:写锁、悲观读锁与乐观读。
StampedLock之所以可以比ReadWrite更快,是因为引入了乐观读(通过long tryOptimisticRead()与boolean validate(stamp)两个方法实现的)。乐观读本质就是无锁编程,使用乐观读性能好,就是因为去掉了加锁的性能开销。
StampedLock使用的注意事项:
从功能上来说,StampedLock是ReadWriteLock的子集,StampedLock只是在读多写少的场景下,性能更优。StampedLock的使用存在着一些约束:
- StampedLock是不可重入的,这从StampedLock没有带Reentrant可以看出来;
- StampedLock不支持条件变量;
- 使用StampedLock时,一定不要使用线程中断方法,这会导致CPU飙升。
StampedLock用法参考:J.U.C之locks框架:StampedLock
ConcurrentSkipListMap
Map接口有两个并发容器的实现类:ConcurrentHashMap和ConcurrentSkipListMap。并发Map内部使用的都是分段加锁的,减小了锁的粒度。相比于同步容器Hashtable,性能要高。ConcurrentHashMap和ConcurrentSkipListMap的区别在于,前者的key是无序的,后者是有序的。从命名就能看到实现原理,前者是Hash,后者是跳表。跳表这种数据结构,很好得实现了有序和时间复杂度之间的平衡。
使用ConcurrentHashMap和ConcurrentSkipListMap需要注意: 1. 二者都不支持key为null,或value为null; 2. 需要有序时使用后者。
Set接口也有两个并发容器的实现类:CopyOnWriteArraySet和ConcurrentSkipListSet
线程安全的队列使用建议
Java中可以用到的所有线程安全队列,从是否阻塞、单双端、是否有界、内部数据结构、是否无锁及特殊功能这六个维度对队列进行了对比,并详细说明了各个队列的特点及使用方式。
基于以上分析,我们对队列的选择建议如下:
按功能场景选择需要的队列
看是否需要阻塞接口,是否需要双端; 需要支持handoff功能的,选择LinkedTransferQueue或SynchronousQueue; 需要优先级出队的,选择PriorityBlockingQueue;需要延迟出队的,选择DelayQueue。
使用有界队列
无界队列可能出现OOM问题,这是一个致命问题。
ArrayBlockingQueue与LinkedBlockingQueue功能一致,建议使用ArrayBlockingQueue
ArrayBlockingQueue以数组为基础,长时间运行对GC压力小,可能有效利用CPU缓存。长时间运行,效果好于LinkedBlockingQueue。
对吞吐量要求高的使用Disruptor
相比于ArrayBlockingQueue,Disruptor的吞吐量是其5到10倍。