您的位置:首页 > 其它

并发容器、同步容器、同步工具类

2015-04-13 21:50 267 查看
一、同步容器类

1.同步容器类包括Vector和Hashtable。这些类实现线程安全的方式是:将它们的状态封装起来,并对每个公有方法都进行同步,使得每次只有一个线程能够访问容器的状态。

2.同步容器类都是线程安全的,但在某些情况下可能需要额外的客户端加锁来保护符合操作。

3.迭代器。对容器类标准的迭代方式都是Iterator。如果有其他线程并发的修改容器,就要在迭代期间对容器加锁。当发现容器在迭代过程中被修改,就会抛出ConcurrentModificationException。具体过程是这样的:将计数器的变化与容器关联起来,如果在迭代期间计数器被修改,那么hasNext()和next()将抛出如上异常。

如果在迭代期间不希望对容器加锁,那么一种替代方法就是“克隆”容器,并在副本上进行迭代。

4.在所有对共享容器进行迭代的地方都要加锁。

二、并发容器

java 5.0提供了多种并发容器类来改进同步容器类的性能。同步容器将所有对容器状态的访问都串行化,以实现线程安全。严重降低并发性,当多个线程竞争容器的锁时,吞吐量将严重降低。因此,增加了些并发容器例如ConcurrentHashMap用来代替同步且基于散列的Map,以及CopyOnWriteArrayList,用于在遍历操作为主要操作的情况下代替同步的List。并在新的ConcurrentMap接口中增加了对一些常见复合操作的支持,例如“没有则添加”,“重复则替换”等。

通过并发容器来代替同步容器,可以极大提高伸缩性并减低风险。

Java5.0增加了两种新的容器类型:Queue 和 BlokingQueue。用来临时保存一组等待处理的元素。它的几种实现:ConcurrentLinkedQueue,是一个传统的FIFO队列。PriorityQueue,是一个非并发的优先队列。Queue上的操作不会阻塞。BlockingQueue扩展了Queue,增加了可阻塞的插入和获取等操作。如果队列为空,那么获取元素的操作将一直阻塞,直到队列中出现一个可用的元素。如果队列已满,那么插入元素的曹邹将一直阻塞直到出现队列出现可用的空间。

与HashMap一样,ConcurrentHashMap也是一个基于散列的Map,但它使用了一种完全不同的加锁策略来提供更高的并发性和伸缩性。ConcurrentHashMap并不是将每个方法都在同一个锁上同步并使得每次只能有一个线程访问容器,而是使用一种粒度更细的加锁机制来实现更大程度的共享,这种机制称为分段锁。在这种机制中,任意数量的读取线程可以并发的访问Map,执行读取操作的线程和执行写入操作的线程可以并发地访问Map,并且一定数量的写入线程可以并发的修改Map。因此它在并发访问环境下将实现更高的吞吐量,它们提供的迭代器不会跑出ConcurrentModificationException,因此不需要再迭代过程中对容器加锁。

CopyOnWriteArrayList用于替代同步List,在迭代器件不需要对容器进行加锁或复制。(类似,CopyOnWriteArraySet代替同步set)每次对容器进行修改是,都会创建并重新发布一个新的容器副本,从而实现可变性。

三、阻塞,中断,同步工具类

当方法跑出InterruptedException时,表示该方法是一个阻塞方法,如果这个方法被中断,那么它将努力提前结束阻塞状态。Thread提供了interrupt方法,用于中断线程或者查询线程是否已经被中断。每个线程都有一个不二类型的属性,表示线程的中断状态,当中断线程时将设置这个状态。

处理对中断的响应,对于库代码来说有两种基本选择:

传递InterruptedException和恢复中断。

四、同步工具类

同步工具类可以是任何一个对象,只要它根据其自身的状态来协调线程的控制流。阻塞队列可以作为同步工具类,其他类型的同步工具类还包括信号量(Semaphore)、栅栏(Barrier)以及闭锁(Latch)。

闭锁是一种同步工具类,可以延迟线程的进度直到其到达终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直是关闭的,并且没有任何线程能够通过,当到达结束状态时,这扇门会打来并允许所有的线程通过。当闭锁到达结束状态后,将不会再改变状态,因此这扇门将永远保持打开状态。闭锁可以用来确保某些活动直到其他活动都完成后才继续执行。

CountDownLatch是一种灵活的闭锁实现。闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,这表示所有需要等待的事件都已发生。

FutureTask也可用作闭锁。

计数信号量(Counting Semaphore)用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。Semaphore中管理者一组虚拟的许可,许可的出事数量可以通过构造函数来指定。在执行操作时可以首先获得许可,并在使用以后释放许可。

栅栏(Barrier)类似于闭锁,区别在于,所有线程必须同时到达栅栏位置才能继续执行。闭锁用于等待事件,而栅栏用于等待其他线程。即闭锁永爱确保一些活动在某个事件结束后进行,栅栏则是将处理同一个问题的线程汇聚在一起并得到同时释放,并且栅栏可以重用。

CyclicBarrier可以使一定数量的参与方反复在栅栏位置汇集。线程到达栅栏位置时调用await方法等待其他线程就位。

——摘自《Java并发编程实战》机械工业出版社
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: