5_ Thread safety for collections

Keywords: Java JUC

1,ArrayList

1.1 thread unsafe demonstration

public class NotSafeDemo {
    //Multiple threads modify the collection at the same time
    public static void main(String[] args) {
        List list = new ArrayList();
        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString());
                System.out.println(list);
            }, "thread " + i).start();
        }
    }
}

Error: java.util.ConcurrentModificationException

1.2 solution Vector

List list = new Vector();

1.3 solution Collections

List list= Collections.synchronizedList(new ArrayList());

1.4. Solution - CopyOnWriteArrayList

Copy on write technology

List list=new CopyOnWriteArrayList<>();
  1. characteristic:

    • It is most suitable for applications with the following characteristics: the List size is usually kept small, read-only operations are far more than variable operations, and inter thread conflicts need to be prevented during traversal.
    • It is thread safe.
    • Because you usually need to copy the entire underlying array, variable operations (add(), set(), remove(), and so on) are expensive.
    • Iterators support immutable operations such as hasNext(), next(), but do not support immutable operations such as remove().
    • Traversal using iterators is fast and does not conflict with other threads. When constructing iterators, iterators rely on invariant array snapshots.
  2. Summary:

    • Low efficiency of exclusive lock: it is solved by the idea of separation of read and write

    • The write thread obtains the lock, and other write threads are blocked

    • Copy ideas
      When we add elements to a container, instead of directly adding them to the current container, we first Copy the current container, Copy a new container, and then add elements to the new container. After adding elements, we point the reference of the original container to the new container.

      At this time, a new problem will be thrown out, that is, the problem of inconsistent data. If the write thread has not had time to write memory, other threads will read dirty data.

  3. Dynamic array mechanism

    • It has a "volatile array" inside to hold data. When "adding / modifying / deleting" data, a new array will be created, and the updated data will be copied to the new array. Finally, the array will be assigned to "volatile array", which is why it is called CopyOnWriteArrayList
    • Because it creates new arrays when "adding / modifying / deleting" data, CopyOnWriteArrayList is inefficient when it involves modifying data; However, it is more efficient to perform only traversal search.
  4. "Thread safety" mechanism

    • Implemented through volatile and mutex.
    • Use the "volatile array" to save the data. When a thread reads the volatile array, it can always see the last write of the volatile variable by other threads; In this way, volatile provides the guarantee of the mechanism that "the data read is always up-to-date".
    • Protect data through mutexes. When "adding / modifying / deleting" data, you will first "obtain the mutex", and then update the data to the "volatile array" after modification, and then "release the mutex", so as to achieve the purpose of protecting data.

2,HashSet

2.1 thread unsafe demonstration

public class NotSafeDemo {
    //Multiple threads modify the collection at the same time
    public static void main(String[] args) {
        Set<String> set=new HashSet<>();
        for(int i=0;i<100;i++){
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0,8));
                System.out.println(set);
            }).start();
        }
    }
}

2.2. Solution CopyOnWriteArraySet

Set<String> set=new CopyOnWriteArraySet<>();

3,HashMap

3.1 thread unsafe demonstration

public class NotSafeDemo {
    //Multiple threads modify the collection at the same time
    public static void main(String[] args) {
        Map<String,String> map=new HashMap<>();
        for(int i=0;i<100;i++){
            String key=String.valueOf(i);
            new Thread(()->{
                map.put(key,UUID.randomUUID().toString().substring(0,8));
                System.out.println(map);
            }).start();
        }
    }
}

3.2. Solution ConcurrentHashMap

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

Posted by sstoveld on Mon, 20 Sep 2021 08:32:54 -0700