同步容器
Java里面提供了一些线程安全类和并发工具,比如:同步容器、并发容器、阻塞队列、Synchronizer(比如CountDownLatch)
同步容器:Vector Stack HashTable
并发容器:ConcurrentHashMap(segment结构的)、CopyOnWriteArrayList
阻塞队列:ArrayBlockingQueue(基于数组)、LinkedBlockingQueue(基于链表)、PriorityBlockingQueue(优先级队列)、DelayQueue(基于PriorityQueue,一种延时阻塞队列)
1、Java非线程安全容器?
Java集合容器框架有4大类:List、Set、Queue、Map(非线程安全的)
List、Set、Queue接口都继承了Collection接口,Map是单独的接口
List:ArrayList(源码:桶数组实现)、LinkedList(链表。包含栈、队列操作。双向链表,实现了Deque接口)
Queue:Deque、PriorityQueue
Set:HashSet、LinkedHashSet、TreeSet(set源码中包含一个Map)
Map:HashMap(解决冲突的方法:链表法Entry链表)、LinkedHashMap、TreeMap(红黑树)
2、Java中的同步容器类
(1)Vector Stack HashTable(采用synchronized方法同步)
(2)Collections类中提供的静态工厂方法创建的类
Vector与ArrayList
但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。且在对Vector等容器并发的进行迭代修改时,会报ConcurrentModificationException异常,但在并发容器(CopyOnWriteArrayList)中不会。
HashTable与HashMap
Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。
StringBuilder与StringBuffer
StringBuilder和StringBuffer的方法是一模一样,就前者是多线程而后者是单线程的。
Stack 继承自Vector 也是线程安全的。
可以由java.util.Collections来创建线程安全的集合,如:
在Collections类中有多个静态方法,它们可以获取通过同步方法封装非同步集合而得到的集合:
public static Collection synchronizedCollention(Collection c)
public static List synchronizedList(list l)
public static Map synchronizedMap(Map m)
public static Set synchronizedSet(Set s)
public static SortedMap synchronizedSortedMap(SortedMap sm)
public static SortedSet synchronizedSortedSet(SortedSet ss)
这些方法基本上返回具有同步集合方法版本的新类。比如,为了创建多线程安全且由ArrayList支持的List,可以使用如下代码:
List list = Collection.synchronizedList(new ArrayList());
ConcurrentModificationException异常
异常发生的原因:
list.remove(integer);//在iterator迭代中,若直接对list进行remove操作则会报异常。因为源码中,list操作的remove会修改modCount(AbstractList类的成员变量),iterator迭代源码中选取next操作时,会先利用checkForComodification()方法判断modCount是否等于expectedModCount,因为list的remove操作使得modCount不等于expectedModCount,所以报错。
关键点就在于:调用list.remove()方法导致modCount和expectedModCount的值不一致。
注意,像使用for-each进行迭代实际上也会出现这种问题。
解决方法:
单线程下,迭代修改时的ConCurrentModificationException异常
iterator.remove(); //因为iterator的remove()方法中有expectedModCount=modCount,这样迭代就不会出错了。
多线程下,迭代修改时的ConCurrentModificationException异常,解决办法:
(1)在使用iterator迭代时使用synchronized或者Lock进行同步
(2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector