并发容器

常用容器

一、ConcurrentHashMap

使用一种粒度更细的加锁机制来实现更大程度的共享,这种机制称为分段锁。在这种机制中,任意数量的读取线程可以并发地访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且一定数量的写入线程可以并发地修改Map。

其带来的结果是,在并发访问的环境下将实现更高的吞吐量,而在单线程环境中只损失非常小的性能。

二、CopyOnWriteArrayList

“写入时复制”,在每次修改时,都会创建并重新发布一个新的容器副本,从而实现可变性。并且返回的元素与迭代器创建时的元素完全一致,而不必考虑修改操作所带来的影响。

用于在遍历操作为主要操作的情况下代替同步的List。

显然,每当修改容器时都会复制底层数据,这需要一定开销,特别是当容器规模较大时。仅当迭代操作远远多于修改操作时,才应该使用“写入时复制”容器。


队列

Java5.0增加了两种新的容器类型:Queue和BlockingQueue。

一、Queue

用来临时保存一组等待处理的元素。它提供了几种实现,包括:ConcurrentLinkedQueue,这是一个传统的先进先出队列,以及PriorityQueue,这是一个(非并发的)优先队列。

通过LinkedList来实现Queue的

二、BlockingQueue

BlockingQueue扩展了Queue,增加了可阻塞的插入和获取等操作。如果队列为空,那么获取元素的操作(take)将一直阻塞,直到队列中出现一个可用的元素。如果队列已满(对于有界队列来说),那么插入元素的操作(put)将一直阻塞,直到队列中出现可用的空间。

  • LinkedBlockingQueue和ArrayBlockingQueue

都是FIFO队列,二者分别与LinkedList和ArrayList类似,但比同步List拥有更好的性能。

  • PriorityBlockingQueue

是一个按优先级排序的队列。既可以根据元素的自然顺序来比较元素(如果它们实现了Comparable方法),也可以使用Comparator来比较。

  • SynchronousQueue

不是一个真正的队列,因为它不会为队列中的元素维护存储空间。与其他队列不同的是,它维护一组线程,这些线程在等待着把元素加入或移除队列。仅当有足够多的消费者,并且总是有一个消费者准备好获取交付的工作时,才适合使用同步队列。


阻塞方法与中断方法

BlockingQueue 的 put 和 take 等方法会抛出受检查异常 InterruptedException,这与类库中其他一些方法的做法相同,例如Thread.sleep。当某方法抛出 InterruptedException 时,表示该方法是一个阻塞方法,如果这个方法被中断,那么它将努力提前结束阻塞状态。

当在代码中调用了一个将抛出 InterruptedException 异常的方法时,你自己的方法也就变成了一个阻塞方法,并且必须要处理对中断的响应。有两种基本选择:

  • 传递InterruptedException。
  • 恢复中断。有时候不能抛出InterruptedException,例如当代码是Runnable的一部分时。如下所示:
public class TaskRunnable implements Runnable{
    BlockingQueue<Task> queue;
    ...
    public void run(){
        try{
            processTask(queue.take());
        }catch(InterruptedException e){
            //恢复被中断的状态
            Thread.currentThread().interrupt();
        }
    }

}
posted @ 2017-04-04 20:42  Lucare  阅读(85)  评论(0编辑  收藏  举报