一、同步容器类
同步容器类包含Vector,Hashtable。以及在JDK1.2中添加的一些功能类似的容器类,他们是由Collections.synchronisedXxx等工厂方法创建的。这些类实现线程安全的方式就是将底层容器类的状态变量封装起来,并且同步每一个公有的方法,使得每次只能有一个线程访问底层容器类的状态变量。
-
同步容器类的问题
在使用同步容器类提供的公共接口的时候,容器类是线程安全的。但是如果需要在现有的接口上组合成新的操作是,容器的线程安全性就有可能遭到破坏:
(1)迭代操作的问题
两个原子操作之间可能存在可能存在另一个线程已经更改vector的内部状态,此时get(i)可能取不到。抛出异常
上述问题还存在条件运算(若没有则添加)等操作中。
二、并发容器类
-
ConcurrentHashMap
(1)ConcurrentHashMap并不是将每个方法都在同一个锁上进行同步并且每次只有一个线程可以访问容器。而是使用了一种更细粒度的加锁机制来最大程度实现容器在线程中的共享,该机制称为分段锁(LockStriping)。在这种机制中,任意数量的读取线程可以并发的访问Map,并且一定数量的写操作线程可以并发的修改Map。从而在多线程环境中带来更高的吞吐量。
(2)ConcurrentHashMap与其他并发容器类一起增强了同步容器类:他们提供的迭代器不会抛出ConcurrentModificationException,因此不需要再迭代过程中对容器进行加锁。ConcurrentModificationException生成的迭代器具有弱一致性,可以迭代器生成后在进行遍历的时候可以容忍其他线程对容器的修改,而不会及时抛出异常。
(3)额外的原子Map操作
-
CopyOnWriteArrayList
以下是关于CopyOnWriteArrayList的相关资料
-
阻塞队列和生产者消费者模式
(1)阻塞队列
Web 便笺来自: http://ifeve.com/java-blocking-queue/.
(2)双端队列与工作密取
-
阻塞方法和中断方法
线程的的阻塞原因有多种,比较常见的阻塞场景如下:线程等待IO操作的完成;线程等待获取一个锁;等待从Thread.sleep()中醒过来。当线程被阻塞时,他通常被挂起并处于一种阻塞状态(Blocked,Waiting或者Timed_Waiting)。阻塞操作与某个执行时间很长的操作区别在于被阻塞的线程必须等待外部某个不受其控制的时间发生(IO操作完成,其他线程释放该线程要获取的锁等)他才能够继续执行。当某个外部事件发生时该线程的状态被置为Runnable,并可以再次被调度执行。
-
同步工具类
同步工具类可以是任何一个对象,只要它根据自身的状态来协调线程的控制流。阻塞队列可以作为同步工具类。其他类型的工具类包括:信号量(Semaphore),栅栏(Barrier)以及闭锁(Latch)
(1)闭锁
Web 便笺来自: http://www.heishou.com.cn/simple/?t156923.html.
(2)FutureTask
Future模式:在现实中,可能会有这样一种应用场景我们开启主线程A去做一件事情,例如浏览网页,在浏览网页的过程中可能需要加载图片和视频,如果我们用串行的方式去执行这个步骤的话,那么必须等待一个图片或者视频加载完成之后才能继续往下浏览网页,这样效率是极低的。因此我们考虑这样一种实现,主线程A会开启另外一个线程去加载图片和视频,当A线程浏览到某个图片的时候直接将副线程的加载结果拿来用即可。
来自:http://blog.csdn.net/ghsau/article/details/7451464
(3)信号量(Semaphore)
信号量的作用是控制同时访问某个资源的操作的个数,或者同时执行某项指定操作数量。Semaphore内部管理着一组虚拟的许可,许可的数目可以在初始化对象的时候有构造函数指定。如果一个共享的资源需要通过Semaphore来控制并发访问的线程数(例如某个对象池每次允许5个线程同时访问,假设现在有10个线程同时运行),那么每次线程需要访问该资源的时候就需要先调用Semaphore上的acquire方法来获取许可,如果现在对象池的并发访问线程数目已经达到最大值,即Semaphore上的许可数目为0,那么该线程会被阻塞,直到有其他线程释放资源,即Semaphore上的许可不为0。线程每次访问完资源之后需要释放许可,调用Semaphore的release()方法来释放许可。
Web便签来自:http://outofmemory.cn/code-snippet/2477/JAVA-xinhaoliang-Semaphore-usage
(4)栅栏