Are collections in JUC thread safe?

1. Examples of thread unsafety of collections

The add method in ArrayList does not have the synchronized keyword, which is thread-unsafe. The source code is as follows:
insert image description here
Demo:

package com.jess.sync;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/**
 * @program: JUC
 * @description: list集合线程不安全
 * @author: Jess
 * @create: 2021-07-23 14:36
 **/
public class ThreadDemo4 {
    
    
    public static void main(String[] args) {
    
    
        //创建ArrayList集合
        List<String> list = new ArrayList<>();
        for (int i = 0; i <30; i++) {
    
    
            new Thread(()->{
    
    
                //向集合添加内容
                list.add(UUID.randomUUID().toString().substring(0,8));
                //从集合获取内容
                System.out.println(list);
            },String.valueOf(i)).start();
        }
	}
}

Code execution error:
insert image description here
ConcurrentModificationException: Concurrent modification exception

2. ArrayList solution

1. Vector solution

This scheme is not commonly used, it is a long-term scheme
insert image description here

public class ThreadDemo4 {
    
    
    public static void main(String[] args) {
    
    
		//Vector解决
        List<String> list = new Vector<>();
        for (int i = 0; i <30; i++) {
    
    
            new Thread(()->{
    
    
                //向集合添加内容
                list.add(UUID.randomUUID().toString().substring(0,8));
                //从集合获取内容
                System.out.println(list);
            },String.valueOf(i)).start();
        }
	}
}

The expansion mechanism of Vector is very similar to that of ArrayList.
insert image description here

If the size of the expanded capacity is specified, the size of the new array to be expanded is the original array plus the size of the expanded capacity. If the size of the expanded capacity is not specified, the size of the new expanded array is twice the size of the original array.

2. Collections solution

uncommonly used

//Collections解决  
//synchronizedList:返回指定列表支持的同步(线程安全的)列表
List<String> list = Collections.synchronizedList(new ArrayList<>());

3*. CopyOnWriteArrayList solution

Common solutions----copy-on-write technology: During the write operation, first copy a copy of the same size as the previous set, write new content into it after copying, and then overwrite the previous set after writing, so as to ensure that the write operation will not affect the read operation. .

All mutable operations (add, set, etc.) of the CopyOnWriteArrayList class are implemented by creating a new copy of the underlying array.

 List<String> list = new CopyOnWriteArrayList<>();

The CopyOnWriteArrayList write operation add() method adds a Lock lock when adding a collection to ensure synchronization and avoid multiple copies when multi-threaded writing.
insert image description here
The read operation does not have any synchronization control and lock operation. The reason is that the internal array array will not be modified, but will only be replaced by another array, so data security can be guaranteed.
insert image description here
insert image description here

Why use CopyOnWriteArrayList instead of Vector?

  1. All methods of operating elements of the Vector collection are added with the synchronized keyword, which leads to very low efficiency of operating Vector. The read operation of CopyOnWriteArrayList is not locked, so the read performance of CopyOnWriteArrayList is much higher than that of Vector.
  2. The size of Vector's expansion each time is twice the size of the original array, while CopyOnWriteArrayList does not need to be expanded, and the array capacity can meet the requirements through the COW idea.

3. HashSet solution

public class ThreadDemo4 {
    
    
    public static void main(String[] args) {
    
    
       // 演示Hashset
        Set<String> set = new HashSet<>();
        for (int i = 0; i <30; i++) {
    
    
            new Thread(()->{
    
    
                //向集合添加内容
                set.add(UUID.randomUUID().toString().substring(0,8));
                //从集合获取内容
                System.out.println(set);
            },String.valueOf(i)).start();
        }
	}
}

Like ArrayList, there are thread safety issues:
insert image description here
add method source code:
insert image description here
The solution is the same as ArrayList:

//工具类解决方法
Set<String> set1 = Collections.synchronizedSet(new HashSet<>());
//juc解决方法 cow
Set<String> set = new CopyOnWriteArraySet<>();

What is the bottom layer of HashSet? That is, the add() method of HashMap
insert image description here
Set is essentially to use PRESENT to isolate the value in the key-value pair, and only put the key of the map, and because the key cannot be repeated, the set is disordered.
insert image description here
insert image description here

4. HashMap solution

HashMap is not safe

Map<String,String> map = new ConcurrentHashMap<>();

Guess you like

Origin blog.csdn.net/myjess/article/details/119034239