6.7同步容器
同步容器中的方法主要是使用synchronized进行同步,从而保证线程安全。
ArrayList、HashMap、List,Set,Map这些常见的线程不安全类的同步容器分别如下
ArrayList → Vector,Stack
HashMap→ HashTable(key,value不能为null)
Collections.synchronizedXXX(List,Set,Map)
可自行编写代码验证同步容器的线程安全性
不过需要注意的是:即使使用了同步容器,有时候不一定能真正的做到线程安全,
如下代码使用了vector同步容器类,但会出现异常,原因是线程B在获取vector某个元素的时候,该元素可能已被线程A移除:
package com.moluo.concurrency.syncContainer;
import com.moluo.concurrency.annotation.NotThreadSafe;
import java.util.Vector;
@NotThreadSafe
public class VectorExample2 {
public static Vector<Integer> vector = new Vector<>();
public static void main(String[] args) throws InterruptedException {
while (true) {
for (int i = 0; i < 10; i++) {
vector.add(i);
}
Thread thread = new Thread(() -> {
for (int i = 0; i < vector.size(); i++) {
vector.remove(i);
}
});
Thread thread1 = new Thread(() -> {
for (int i = 0; i < vector.size(); i++) {
vector.get(i);
}
});
thread.start();
thread1.start();
}
}
}
同时建议:在做遍历的时候,尽量不要做更新操作,不然很可能出问题。如下例:
package com.moluo.concurrency.syncContainer;
import com.moluo.concurrency.annotation.NotThreadSafe;
import java.util.Iterator;
import java.util.Vector;
@NotThreadSafe
public class VectorExample3 {
// 抛出异常java.util.ConcurrentModificationException
public static void test1(Vector<Integer> vector) { // foreach
for (Integer integer : vector) {
if (integer.equals(3)) {
vector.remove(integer);
}
}
}
// 抛出异常java.util.ConcurrentModificationException
public static void test2(Vector<Integer> vector) { // iterator
Iterator<Integer> iterator = vector.iterator();
while (iterator.hasNext()) {
Integer integer = iterator.next();
if (integer.equals(3)) {
vector.remove(integer);
}
}
}
// 正常运行
public static void test3(Vector<Integer> vector) {
for (int i = 0; i < vector.size(); i++) {
if (vector.get(i).equals(3)) {
vector.remove(i);
}
}
}
public static void main(String[] args) throws InterruptedException {
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
vector.add(3);
test1(vector);
// test2(vector);
// test3(vector);
}
}
如果一定要做更新操作,建议在遍历过程中做好标记,等遍历完后,再取出标记值做更新操作
同步容器缺点
同步容器中的方法主要是使用synchronized进行同步,那么势必会带来性能问题。同时我们演示了同步容器不一定能真正的做到线程安全
推荐方式
在实际的项目中,同步容器我们会使用,但已经越来越少了,通常我们会选用并发容器来代替同步容器
Last updated
Was this helpful?