接上一篇

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. UNIX网络编程——套接字选项(心跳检测、绑定地址复用)

    /* 设置套接字选项周期性消息检测连通性 心跳包. 心博.主要用于长连接. * 参数:套接字, 1或0开启, 首次间隔时间, 两次间隔时间, 断开次数 */ void setKeepAlive( in ...

  2. 偏置方差分解Bias-variance Decomposition

    http://blog.csdn.net/pipisorry/article/details/50638749 偏置-方差分解(Bias-Variance Decomposition) 偏置-方差分解 ...

  3. printf函数压栈解惑

    最近看到一些程序员的笔试题目,经常会考到printf函数的参数压栈问题,总体来讲就是参数从右向左依次压栈,再出栈,但是今天看到一个看似很简单的题目,却一直找不到头绪.题目如下: #include &l ...

  4. UNIX环境高级编程——sigqueue、sigsuspend函数

    一.sigqueue函数 功能:新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用. int sigqueue(pid_t pid, int sig, ...

  5. LTP语法分析

    http://blog.csdn.net/pipisorry/article/details/50306931 POS词性标注解释 词性标注(Part-of-speech Tagging, POS)是 ...

  6. Demand Side Platform

    DSP特点: DSP不是从网络媒体那里包买广告位,也不是采用CPD(Cost Per Day)的方式获得广告位:而是从广告交易平台(AdExchange)来通过实时竞价的方式获得对广告进行曝光的机会, ...

  7. 【leetcode73】经典算法-Guess Number Higher or Lower

    题目描述: 从1-n中,随便的拿出一个数字,你来猜测. 提示 提供一个guess(int num)的api,针对猜测的数字,返回三个数值.0,-1,1 0;猜中返回num -1:比猜测的数值小 1:比 ...

  8. [C#]ToString("##")格式化用法案例一:自动编码单据流水码

    之前的写的自动编码单据流水码是写在存储过程或者函数中的,今天用程序写一个发现TOSTRING可以格式化方便. /// <summary> /// 年月日+两位流水码 /// </su ...

  9. 【Unity Shaders】Diffuse Shading——使用2D ramp texture来创建一个假的BRDF(双向反射分布函数)

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  10. (二十)即时通信的聊天气泡的实现I

    Tip:通过xib和storyboard不可能将一个控件作为ImageView的子控件,只能通过代码的addSubview方法实现. 设置图片的细节:如果button比图片大(为了方便对齐),将图片设 ...