当前位置: 首页 > 图灵资讯 > 技术篇> 多线程中的同步容器和并发容器

多线程中的同步容器和并发容器

来源:图灵教育
时间:2023-04-09 09:40:46

Java并发编程,我们经常听同步容器和并发容器的说法,我们不禁提问:什么是同步容器和并发容器

同步容器可以简单地理解为synchronized实现同步容器。同步容器会导致多线程中串行执行容器方法,降低并发性,因为它们都是锁定容器本身的对象,所以可以考虑在需要支持并发性的环境中使用并发性容器。并发容器是为多线程并发访问而设计的。concurent包引入jdk5.0,提供了许多并发容器,如concurenthashmap、copyonWriteArayList等。

由于使用容器时同步处理不便,同步容器的出现。在Java的集合容器框架中,Listtt主要有四大类、Set、Queue、Map。其中List、Set、Queue继承了Collection顶层接口,Map本身就是顶层接口。我们常用的ArrayListt、LinkedList、Hashmap这些容器都是非线程安全的,如果有多个线程并发访问这些容器,就会出现问题。因此,在编写程序时,必须要求开发人员在任何访问该容器的地方手动同步,导致使用该容器的不便。因此,Java为用户提供了同步容器。同步容器串行访问所有容器状态,确保线程安全,并严重减少并发性。当多个线程竞争容器时,吞吐量严重减少。从JDK5开始,为多线程并发访问提供并发容器,并引入java.util.concurrent 包。

同步容器和并发容器为多线程并发访问提供了合适的线程安全性,但并发容器具有更高的可扩展性。在在Java5之前,程序员只有同步容器,并在多线程并发访问中引起争议,阻碍了系统的可扩展性。Java5介绍了并发容器。并发容器采用与同步容器完全不同的锁定策略,提供更高的并发性和可伸缩性。例如,在ConcurentHashmap中使用了一种粒度更细的锁定机制,可称为分段锁。在这种锁定机制下,允许任何数量的读线程并发访问map,读写操作的线程也可以并发访问map。同时,允许一定数量的编写操作线程并发修改map,因此可以在并发环境中实现更高的吞吐量。此外,并发容器还提供了一些复合操作,包括putifabsent,在使用同步容器时需要自己实现。然而,由于并发容器不能通过加锁独家访问,我们无法通过加锁实现其他复合操作。

java中的同步容器类:

1、Vector、Stack、HashTable

2、Collections提供的静态工厂方法创建的类别

Vector实现了List接口,实际上是一个类似ArrayList的数组,但Vector中的方法是synchronized。Stack也是同步容器,其实Stack是继承Vector的。Hashtable也同步处理,但Hashmap没有。Collections类是一种工具提供类,包括对集合或容器进行排序、搜索等操作。重要的是,它还提供了几种创建同步容器的静态工厂方法。同步容器不可避免地会有一些缺陷,采用同步容器中的方法synchronized同步,会影响执行性能。而且同步容器不一定是真正完整的线程安全。同步容器中的方法是线程安全,但这些集合操作不能保证其线程安全,仍需主动锁定。Vector等容器迭代,修改span>会出现同步容器 concurentmodificationexception异常。在多线程条件下,为了避免这种异常,可以在使用iterator迭代时使用synchronized或lock同步,并发容器copyonwritearaylist代替araylist和vector。

ConcurrentHashMap取代同步Map。Hashmap根据散列值分段存储,同步Map同步时锁定所有段,而ConcurentHashmap根据散列值锁定散列值对应段,提高并发性能。ConcurrentHashmap为常用操作提供支持。比如"如果没有,则添加":putIfAbsent(),替换:replace()。这两个操作都是原子操作。与Vector和Hashtable、Collection.synchronizedXxx()与同步容器等相比,util.concurent中的并发容器可以根据具体场景设计,尽量避免synchronized提供并发性。同时可以定义一些并发安全的复合操作,保证并发环境下的迭代操作不会出错。util.concurrent中容器迭代时,不能在synchronized中包装,可以保证不抛异常,但不一定每次都能看到最新的数据。

并发容器是为了解决同步容器的性能问题,提高程序的吞吐量。同步容器是为了实现java多线程访问非线程安全容器时的同步性。两者相辅相成,缺一不可。只有掌握并发容器和同步容器,才能完全实现多线程的并发性和同步性,在提高多线程性能的同时保证线程安全。