java并发:同步容器&并发容器

同步容器、并发容器

在Java并发编程中,经常听到同步容器、并发容器之说,那什么是同步容器与并发容器呢?

同步容器

  同步容器可以简单地理解为通过synchronized来实现同步的容器,比如Vector、Hashtable以及SynchronizedList等,如果有多个线程调用同步容器的方法,它们将会串行执行。

  通过查看Vector、Hashtable等同步容器的实现代码,可以看到这些容器实现线程安全的方式是将它们的状态封装起来,并在需要同步的方法上加上关键字synchronized。

  在某些情况下,同步容器不一定就是线程安全的,比如获取最后一个元素或者删除最后一个元素需要额外的同步操作:

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);  
} 

  虽然上面的方法看起来没有问题,Vector自身的方法也是同步的,但是在多线程环境中还是隐藏着问题。

  如果有两个线程A、B同时调用上面的两个方法,假设list的大小为10,这里计算得到的lastIndex为9,线程B首先执行了删除操作(多线程之间操作执行的不确定性导致),而后线程A调用了list.get方法,这时就会发生数组越界异常;导致问题的原因是上面的操作不是原子操作,这里可以通过在方法内部使用list对象锁来实现原子操作。

  同步容器会导致多个线程中对容器方法调用的串行执行,降低并发性,因为它们都是以容器自身对象为锁,所以在需要支持并发的环境中,可以考虑使用并发容器来替代。

并发容器

  并发容器是针对多个线程并发访问而设计的,在jdk5.0引入了concurrent包,其中提供了很多并发容器,如ConcurrentHashMap、CopyOnWriteArrayList等。

  其实同步容器与并发容器都为多线程并发访问提供合适的线程安全,不过并发容器的可扩展性更高。

  在Java5之前,程序员们只有同步容器,在多线程并发访问的时候会导致争用,阻碍了系统的扩展性。

  Java5介绍了并发容器,并发容器使用了与同步容器完全不同的加锁策略来提供更高的并发性和伸缩性。

  例如,在ConcurrentHashMap中采用了一种粒度更细的加锁机制,可以称为分段锁,在这种锁机制下,允许任意数量的读线程并发地访问map,并且执行读操作的线程与执行写操作的线程可以并发的访问map,同时允许一定数量的写操作线程并发地修改map,所以它可以在并发环境下实现更高的吞吐量。

  另外,并发容器提供了一些在使用同步容器时需要自己实现的复合操作,包括putIfAbsent等。

  由于并发容器不能通过加锁来独占访问,所以无法通过加锁来实现其他复合操作了。

posted @ 2016-04-14 09:24  时空穿越者  阅读(5179)  评论(1编辑  收藏  举报