1.同步类容器:vector和hashTable
原理:将他们的状态封装起来,对每个公有方法都进行同步,使得每次只要一个线程能访问容器的状态。
同步类容器存在的问题:容器类上常见的符合操作:迭代、跳转、条件运算等,在执行这些符合操作时,其它线程可能会并发的修改容器,会有可能抛出异常(ConcurrentModificationException)。
解决办法:通过获得容器类的锁,把复合操作变成原子操作;客户端通过加锁来解决不可靠的迭代问题。缺点:降低并发性。如果不想加锁的话可以采用克隆容器,让复合操作在副本上进行。
synchronized(vector){
for(int i=0;i<vector.size();i++)
{
dosomething....
}
}
2.并发类容器
通过并发容器来代替同步容器可以极大提高伸缩性并降低风险。
BlockingQueue:扩展了Queue,增加了可阻塞的插入和获取操作。
ConcurrentHashMap:使用分段锁(一种粒度更细的加锁机制)来实现更大程度的共享,在这种机制中任意数量的读或写都可以访问map。缺点:返回的迭代器具有弱一致性,而并非“即时失败”。比如:size()和inempty()的结果返回的计算值已经过时(比如:返回的是2毫秒前的值),返回的是一个估算值。
注意:ConcurrentHashMap不能被加锁类执行独占空间,因此一些常见的符合操作,如:“若没有则添加”需要使用concurrentMap。
copyOnArrayList:用于替代同步list。原理:每次修改时都会创建并重新发布一个新的容器副本,从而实现可变性。缺点:每次修改都复制底层数组,存在开销。
3.阻塞方法和中断方法
当某个方法抛出Interrupted-exception时,表示该方法是一个阻塞方法。
Thread提供了interrupt方法,用于中断线程或者查询线程是否已经别中断。
当代码中调用了一个会抛出InteeruptedException异常的方法时,你自己的方法也会变成阻塞方法,并且必须要处理对中断的响应。处理方法:传递InterruptedException和恢复中断。
4.同步工具类
同步工具类可以是任何一种对象,只要它根据自身的状态来协调线程的控制流(比如:阻塞队列控制生产者-消费者)。具有代表性的有:阻塞队列、闭锁、信号量、栅栏。
闭锁:可以延迟现成的进度直到其到达最终状态。它相当于一扇门,在闭锁到达状态结束之前门是关的,到达状态后门才打开。比如:countDownLatch、futureTask.
计数信号量(couting semaphore):用来控制同时访问某个特定资源的操作数量,或者同时执行某个操作的数量。一般用于实现资源池类的操作。
栅栏:类似于闭锁,它能阻塞一组线程直到某件事发生。它与闭锁的区别是:所有线程必须同时到达栅栏位置时才继续执行。闭锁用于等待事件,而栅栏用于等待线程。比如:cyclicBarrier.