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?