接上一篇

java并发包小结(一)http://blog.csdn.net/aalansehaiyang52/article/details/8877579

Future 接口
Future 接口允许表示已经完成的任务、正在执行过程中的任务或者尚未开始执行的任务。通过 Future 接口,可以尝试取消尚未完成的任务,查询任务已经完成还是取消了,以及提取(或等待)任务的结果值。
FutureTask 类实现了 Future,并包含一些构造函数,允许将 Runnable 或 Callable(会产生结果的 Runnable)和 Future 接口封装。因为 FutureTask 也实现 Runnable,所以可以只将 FutureTask 提供给 Executor。一些提交方法(如 ExecutorService.submit())除了提交任务之外,还将返回 Future 接口。
Future.get() 方法获取任务计算的结果(或如果任务完成,但有异常,则抛出 ExecutionException)。如果任务尚未完成,那么 Future.get() 将被阻塞,直到任务完成;如果任务已经完成,那么它将立即返回结果。

使用 Future 构建缓存
该示例代码与 java.util.concurrent 中的多个类关联,突出显示了 Future 的功能。它实现缓存,使用 Future 描述缓存值,该值可能已经计算,或者可能在其他线程中'正在构造'。
它利用 ConcurrentHashMap 中的原子 putIfAbsent() 方法,确保仅有一个线程试图计算给定关键字的值。如果其他线程随后请求同一关键字的值,它仅能等待(通过 Future.get() 的帮助)第一个线程完成。因此两个线程不会计算相同的值。

  1. public class Cache {
  2. ConcurrentMap  map = new ConcurrentHashMap();
  3. Executor executor = Executors.newFixedThreadPool(8);
  4. public V get(final K key) {
  5. FutureTask f = map.get(key);
  6. if (f == null) {
  7. Callable c = new Callable() {
  8. public V call() {
  9. // return value associated with key
  10. }
  11. };
  12. f = new FutureTask(c);
  13. FutureTask old = map.putIfAbsent(key, f);
  14. if (old == null)
  15. executor.execute(f);
  16. else
  17. f = old;
  18. }
  19. return f.get();
  20. }
  21. }

Semaphore
Semaphore 类实现标准 Dijkstra 计数信号。计数信号可以认为具有一定数量的许可权,该许可权可以获得或释放。如果有剩余的许可权,acquire() 方法将成功,否则该方法将被阻塞,直到有可用的许可权(通过其他线程释放许可权)。线程一次可以获得多个许可权。
注意信号不跟踪哪个线程拥有多少许可权;这由应用程序来决定,以确保何时线程释放许可权,该信号表示其他线程拥有许可权或者正在释放许可权,以及其他线程知道它的许可权已释放。

CountdownLatch
CountdownLatch 类与 CyclicBarrier 相似,因为它的角色是对已经在它们中间分摊了问题的一组线程进行协调。它也是使用整型变量构造的,指明计数的初始值,但是与 CyclicBarrier 不同的是,CountdownLatch 不能重新使用。
其中,CyclicBarrier 是到达屏障的所有线程的大门,只有当所有线程都已经到达屏障或屏障被打破时,才允许这些线程通过,CountdownLatch 将到达和等待功能分离。任何线程都可以通过调用 countDown() 减少当前计数,这种不会阻塞线程,而只是减少计数。await() 方法的行为与 CyclicBarrier.await() 稍微有所不同,调用 await() 任何线程都会被阻塞,直到闩锁计数减少为零,在该点等待的所有线程才被释放,对 await() 的后续调用将立即返回。
当问题已经分解为许多部分,每个线程都被分配一部分计算时,CountdownLatch非常有用。在工作线程结束时,它们将减少计数,协调线程可以在闩锁处等待当前这一批计算结束,然后继续移至下一批计算。
相反地,具有计数 1 的 CountdownLatch 类可以用作'启动大门',来立即启动一组线程;工作线程可以在闩锁处等待,协调线程减少计数,从而立即释放所有工作线程。下例使用两个 CountdownLatche。一个作为启动大门,一个在所有工作线程结束时释放线程:

  1. class Driver { // ...
  2. void main() throws InterruptedException {
  3. CountDownLatch startSignal = new CountDownLatch(1);
  4. CountDownLatch doneSignal = new CountDownLatch(N);
  5. for (int i = 0; i < N; ++i) // create and start threads
  6. new Thread(new Worker(startSignal, doneSignal)).start();
  7. doSomethingElse();            // don't let them run yet
  8. startSignal.countDown();      // let all threads proceed
  9. doSomethingElse();
  10. doneSignal.await();           // wait for all to finish
  11. }
  12. }
  13. class Worker implements Runnable {
  14. private final CountDownLatch startSignal;
  15. private final CountDownLatch doneSignal;
  16. Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
  17. this.startSignal = startSignal;
  18. this.doneSignal = doneSignal;
  19. }
  20. public void run() {
  21. try {
  22. startSignal.await();
  23. doWork();
  24. doneSignal.countDown();
  25. } catch (InterruptedException ex) {} // return;
  26. }
  27. }

Hashtable 与 ConcurrentHashMap
作为可伸缩性的例子,ConcurrentHashMap 实现设计的可伸缩性要比其线程安全的上一代 Hashtable 的可伸缩性强得多。Hashtable 一次只允许一个线程访问 Map;ConcurrentHashMap 允许多个读者并发执行,读者与写入者并发执行,以及一些写入者并发执行。因此,如果许多线程频繁访问共享映射,使用 ConcurrentHashMap 的总的吞吐量要比使用 Hashtable 的好。
下表大致说明了 Hashtable 和 ConcurrentHashMap 之间的可伸缩性差别。在每次运行时,N 个线程并发执行紧密循环,它们从 Hashtable 或 ConcurrentHashMap 中检索随即关键字,60% 的失败检索将执行 put() 操作,2% 的成功检索执行 remove() 操作。测试在运行 Linux 的双处理器 Xeon 系统中执行。数据显示 10,000,000 个迭代的运行时间,对于 ConcurrentHashMap,标准化为一个线程的情况。可以看到直到许多线程,ConcurrentHashMap 的性能仍保持可伸缩性,而 Hashtable 的性能在出现锁定竞争时几乎立即下降。
与通常的服务器应用程序相比,这个测试中的线程数看起来很少。然而,因为每个线程未进行其他操作,仅是重复地选择使用该表,所以这样可以模拟在执行一些实际工作的情况下使用该表的大量线程的竞争。

线程 ConcurrentHashMap Hashtable
1 1.0 1.51
2 1.44 17.09
4 1.83 29.9
8 4.06 54.06
16 7.5 119.44
32 15.32 237.2

java并发包小结(二)的更多相关文章

  1. java并发包小结(一)

    java.util.concurrent 包含许多线程安全.高性能的并发构建块.换句话讲,创建 java.util.concurrent 的目的就是要实现 Collection 框架对数据结构所执行的 ...

  2. 深入浅出Java并发包—锁机制(二)

    接上文<深入浅出Java并发包—锁机制(一)  >  2.Sync.FairSync.TryAcquire(公平锁) 我们直接来看代码 protected final boolean tr ...

  3. Java并发包中常用类小结(一)

    从JDK1.5以后,Java为我们引入了一个并发包,用于解决实际开发中经常用到的并发问题,那我们今天就来简单看一下相关的一些常见类的使用情况. 1.ConcurrentHashMap Concurre ...

  4. Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

    经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...

  5. Java并发包源码学习之AQS框架(一)概述

    AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer这个类. 阅读Java的并发包源码你会发现这个类是整个java.util.con ...

  6. 深入浅出Java并发包—锁机制(三)

    接上文<深入浅出Java并发包—锁机制(二)>  由锁衍生的下一个对象是条件变量,这个对象的存在很大程度上是为了解决Object.wait/notify/notifyAll难以使用的问题. ...

  7. 深入浅出Java并发包—CAS机制

    在JDK1.5之前.Java主要靠synchronized这个关键字保证同步,已解决多线程下的线程不安全问题,但是这会导致锁的发生,会引发一些个性能问题. 锁主要存在一下问题 (1)在多线程竞争下,加 ...

  8. 对着java并发包写.net并发包之原子类型实现

    众所周知,java1.5并发包通过volatile+CAS原理提供了优雅的并发支持.今天仔细想想.net也有volatile关键字保证内存的可见性,同时也有Interlocked提供了CAS的API, ...

  9. Java SE之XML<二>XML DOM与SAX解析

    [文档整理系列] Java SE之XML<二>XML DOM与SAX解析 XML编程:CRUD(Create Read Update Delete) XML解析的两种常见方式: DOM(D ...

随机推荐

  1. SSH深度历险(七) 剖析SSH核心原理(一)

    接触SSH有一段时间了,但是对于其原理,之前说不出来莫模模糊糊(不能使用自己的语言描述出来的就是没有掌握),在视频和GXPT学习,主要是实现了代码,一些原理性的内容还是欠缺的,这几天我自己也一直在反问 ...

  2. Dynamics CRM 报表导出EXCEL 列合并问题的解决方法

    CRM中的报表导出功能提供了多种格式,excel就是其中之一,这次遇到的问题是导出后打开excel列明合并的问题,具体如下看着相当不美观,物料名称字段占了AB两列,品牌占了CD两列等等. 该问题的源头 ...

  3. UNIX网络编程——TCP连接的建立和断开、滑动窗口

    一.TCP段格式: TCP的段格式如下图所示: 源端口号与目的端口号:源端口号和目的端口号,加上IP首部的源IP地址和目的IP地址唯一确定一个TCP连接. 序号:序号表示在这个报文段中的第一个数据字节 ...

  4. 小强的HTML5移动开发之路(20)——HTML5 Web SQL Database

    来自:http://blog.csdn.net/dawanganban/article/details/18220761 一.Web Database介绍 WebSQL数据库API实际上不是HTML5 ...

  5. Leetcode_172_Factorial Trailing Zeroes

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42417535 Given an integer n, re ...

  6. React native开发中常见的错误

    react native环境搭建请移步:react native环境搭建 这里说说react native创建完成之后,运行中出现的常见问题, 问题1: java.lang.RuntimeExcept ...

  7. Java关键字之finalize

    Java中提供了finalize方法,在垃圾回收器在进行内存释放时会首先调用finalize,但会有一些误区. 1).对象可能不被垃圾回收. 2).垃圾回收并不等于"析构",fin ...

  8. Leetcode_141_Linked List Cycle

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42833739 Given a linked list, d ...

  9. Android应用---基于NDK的samples例程hello-jni学习NDK开发

    Android应用---基于NDK的samples例程hello-jni学习NDK开发 NDK下载地址:http://developer.android.com/tools/sdk/ndk/index ...

  10. 关于SMALI语法

    dalvik字节码有两种类型,原始类型和引用类型.对象和数组是引用类型,其它都是原始类型.V  void,只能用于返回值类型Z  booleanB  byteS  shortC  charI  int ...