Chapter3 集合的线程不安全问题

3.1 ArrayList

  1. 举例说明其线程不安全
    public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            for (int i = 0; i < 300; i++) {
                new Thread(()->{
                    list.add(UUID.randomUUID().toString().substring(0,8));
                    System.out.println(list);
                }, String.valueOf(i)).start();
            }
        }
    报错:

    ConcurrentModificationException(并发修改异常)

  2. 解决方法
    • 使用 Vector 代替 ArrayList :Vector使用了synchronsized
    • 使用 Collections工具类:
      List<String> list = Collections.synchronizedList(new ArrayList<>());
    • 使用CopyOnWriteArrayList代替 ArrayList
      List<String> list = new CopyOnWriteArrayList();

3.2 HashSet

  1. 举例说明其线程不安全
    public static void main(String[] args) {
         Set<String> set = new HashSet<>();
         for (int i = 0; i < 300; i++) {
             new Thread(()->{
                 set.add(UUID.randomUUID().toString().substring(0,8));
                 System.out.println(set);
             }, String.valueOf(i)).start();
         }
     }
    Hashset底层为HashMapvalue为常量。
  2. 解决方法
    • 使用 Collections工具类:
      Set<String> set = Collections.synchronizedSet(new HashSet<>());
    • 使用CopyOnWriteArraySet代替 HashSet
      Set<String> set = new CopyOnWriteArraySet();

3.3 HashMap

  1. 举例说明其不安全
    public static void main(String[] args) {
        Map<String,String> map = new java.util.HashMap();
        for (int i = 0; i < 300; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }).start();
        }
    }
  2. 解决方法
    • Map<String,String> map = new ConcurrentHashMap<>();