java并发编程实战(二)

来源:互联网 发布:vivo手机怎么改mac地址 编辑:程序博客网 时间:2024/06/05 09:30

java并发编程中常常会用到两种容器来存放一些数据,这些数据需要保证能在多线程下正常访问。常见的容器分为两类:同步容器和并发容器。在java并发编程实战一书中的第五章也有讲解。

什么是同步容器以及优劣势

顾名思义同步容器是可以保证数据同步的一类容器,最常见的是hashtable和vector他们被称为同步容器类。看到hashtable、vector就会想到Java的集合框架,我们知道java的集合框架中 list(数组)、set(集合)、queue(队列)都是继承collection,map本身就是接口,常见的比如ArrayList、linkedlist、hashset、hashmap都不是同步容器。当根据Collections.synchronizedxxx工厂方法进行创建的类可以称为同步容器类,他们的方法使用synchronized修饰比如Collections.synchronizedlist。使用同步容器的优点就是可以方便的对容器进行同步操作,不需要手动进行同步。最大的缺点就是性能降低同时多线程访问同步容器也不一定就是线程安全的,比如两个线程同时去操作vector一个线程去获取最后一个元素,另一个线程去删除最后一个元素就可能会出现arrayindexoutofboundsexception异常信息,因为这两个操作都是复合操作,每一个操作都需要知道vector的size长度,此时已不能保证操作的原子性,若想保证线程安全还需要再额外加锁来保证原子性。

java5.0以后提供了并发容器来解决这一难题。

常用的并发容器concurrenthashmap、copyonwritearraylist等,concurrenthashmap的不是简单的使用synchronized进行加锁,而是采用分段锁机制来为map数据结构提供更好的并发性和吞吐量。在java并发编程实战上也有描述

但是当使用concurrenthashmap时应注意使用size和isempty方法,concurrenthashmap返回的迭代器具有弱一致性,因为多个容器并发访问时,size总是在变化的,相对于计算时的结果是过期的,它仅仅表示一个接近值,在并发编程中一般也用不到size和isempty这些方法。

copyonwritearraylist(写时复制的原理)适用于读取较多,数据量较小的情况下。copyonwritearraylist是在写时复制一份来操作,操作完成后再覆盖原来的数据。如果数据量特别并且频繁地写多会占用大量内存。

提一下threadlocal:线程本地变量,它在每一个线程中都会创建一个副本,线程只需要访问自己内部的变量即可。最常使用场景时数据库连接,我们知道数据库连接获取到的connection不是线程安全的,比如多个线程同时访问一个数据库操作公共类(不使用数据库连接池和ThreadLocal的前提下),就有可能一个线程使用connect操作数据库,另一个线程去关闭connection,这就造成了线程安全问题。使用threadlocal为每一个线程获取一个本地变量这样每个线程操作的都是自己内部的变量也就不存在线程安全的问题了,每次获取连接时先到ThreadLocal中去get connection若没有再去获取,释放连接时也要删除掉threadlocal中的connection。