1、同步容器类 一、早期的同步容器类Vector ,Hashtable,相似于Collections.synchronizedXxxx方法建立的,就是用装饰器模式把线程不安全的容器类包装起来,全部公共方法都进行同步,这种容器性能较低。数组
二、同步容器来的问题(复合操做依然会致使混乱的结果) Vector是线程安全的,只是说明Vector自己不会被并发操做破坏,但这不等于并发操做就没有问题。例如以下两个方法被多线程操做:安全
public static Object getLast(Vector list){ //第一步 int lastIndex = list.size() - 1; //第二步 return list.get(lastIndex); } public static void deleteLast(Vector list){ //第一步 int lastIndex = list.size() - 1; //第二步 list.remove(lastIndex); }
线程A执行第一步完,还没有执行第二步;线程B执行了第一步,再执行第二步完;以后线程A再执行第二步,这个时序就会出现问题集合元素个数变了而线程A不知道,会跑出数组越界异常,由于这些操做不是原子性。经过给被操做容器类加锁能够把这些复合操做变成原子操做(但其实Vector状态没有被破坏):多线程
public static Object getLast(Vector list){ synchronized(list){ int lastIndex = list.size() - 1; return list.get(lastIndex); } } public static void deleteLast(Vector list){ synchronized(list){ int lastIndex = list.size() - 1; list.remove(lastIndex); }
迭代操做也会出现多线程操做致使混乱的问题,在迭代操做上加锁保护起来解决问题,可是下降了并发性。并发
//可能会被多线程操做而混乱结果,由于迭代是复合操做,不是原子操做 for(int i = 0;i < vector.size();i++){ //TODO } //加锁锁住这个vector便可,可是下降了并发性,其余线程不能操做vector synchronized(vector){ for(int i = 0;i < vector.size();i++){ //TODO } }
迭代器与ConcurrentModificationException:即便是同步容器类也没有考虑并发修改问题,对应策略是'fail-fast'快速失败,当发现容器被修改时就抛出异常。改善这种状况能够在迭代时对容器进行克隆,迭代副本。 给容器加锁来进行迭代涉及面太广了,不合适,并且有些迭代器操做是隐藏的,容易被忽视。dom
public class HiddenIteratro { @GuardedBy("this") private final Set<Integer> set = new HashSet<Integer>(); public synchronized void add(Integer i) { set.add(i); } public synchronized void remove(Integer i) { set.remove(i); } public void addTenThings(){ Random r = new Random(); for(int i=0;i<10;i++) add(r.nextInt()); System.out.println("DEBUG: added ten elements to " + set); } }
容器的hashCode和equals方法,将容器总体放入其余容器,containsAll、removeAll、retainAll等等方法,以及把容器做为参数的构造函数,都会隐含对容器进行迭代,这些迭代都有可能抛出ConcurrentModificationException。函数
2、并发容器 一、ConcurrentHashMap,使用了分段锁,能够支持任意数量的读线程操做Map;支持多个读线程和写入线程操做Map;能够支持必定数量写入线程同时操做Map,迭代操做不会加锁,采用了弱一致性而不是快速失败,提升了并发性和吞吐量。并发Map还提供了一些复合原子操做,好比存在则删除,存在则替换,不存在则插入等等。 二、CopyOnWriteList,CopyOnWriteHashSet:支持并发操做,迭代不会加锁。工具
3、阻塞队列和生产者消费者模型 生产者消费者模型的阻塞队列实现了可变对象的线程封闭:开始是只有放入对象的生产者线程能访问可变对象,放入以后生产者再也不访问可变对象;后面是只有消费者线程能够访问可变对象,实现了可变对象在线程之间安全的传递。性能
4、阻塞方法或者中断方法 等待I/O操做结束,等待锁,等待Thread.sleep方法中醒来,等待另外一个线程的计算结果(Blocked,Waiting,Timed_Waiting)。方法抛出受检查异常InterruptedException,说明该方法是一个阻塞方法,若是这个方法被中断,它将努力提早结束阻塞状态。抛出该异常后有两个处理策略: 传递异常; 恢复中断状态。this
5、同步工具类 一、闭锁(CountDownLatch):countDown方法递减计数器,await方法等待计数器达到零。 二、FutureTask:也能够用做闭锁,FutureTask有三种状态Waiting to run , running , Completed(完成包括正常结束、因为取消而结束、因为异常而结束)。 三、计数信号量(Counting Semaphore),控制同时访问某个特定资源的操做数量,还可用来实现某种资源池,或者对容器施加边界。线程