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?