Why ArrayList thread safe

The following code is executed, how about the program? ?

package VolatilePkg;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author Heian
 * @time 19/01/22 10:27
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:ArrayList 线程为什么不安全?
 */
public class VolatileTest {
    static List<Integer> list = new ArrayList<> ();
    //static List<Integer> list = new Vector<> ();
    public  void add(){
        for (int i=0;i<1000;i++){
            list.add (1);
        }
    }

    public static void test() throws InterruptedException{
        VolatileTest vo = new VolatileTest ();
        IntStream.range (0,5).forEach (value -> new Thread (() -> vo.add (),String.valueOf (value)).start ());
        while (Thread.activeCount ()>1){
            Thread.yield ();
        }
        System.out.println (list.size ());

    }

    public static void main(String[] args) throws InterruptedException{
       VolatileTest.test ();
    }


}

If the thread-safe output is 5000, but output in three ways:

  1. Less than 5000
  2. 5000
  3. Less than 5000 + ArrayIndexOutOfBoundsException

ArrayList can be seen that in the case of multiple threads of operation, can not ensure data integrity. To add source code analysis:

  public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 1
        elementData[size++] = e;           // 2
        return true;
    }

ArrayList insecurity is mainly reflected in two aspects: Adapted from: https: //www.jianshu.com/p/41be1efe5d65

One reason : mark 2 is not an atomic operation, JMM and read only guarantee the basic atomic assignment, the other not guaranteed, this can be split into two steps:

elementData[size] = e;
size++;

    Single-threaded implementation of the code no problem, but to a multi-threaded environment may have a problem. One thread may overwrite the value of another thread.

  1. The list is empty size = 0.
  2. Executing the thread A elementData[size] = e;suspended after. The A "a" in the index for the 0 position. At this size = 0.
  3. B thread of execution elementData[size] = e;because the size = 0, so the B "b" in the index for the 0 position, then just the data A to the overwritten.
  4. Thread size the value B 1 is increased.
  5. A thread size is increased to a value of 2.

    This way, when the ideal case after the thread A and thread B are executed should be completed "a" at an index position 0, "b" is marked 1 position. The reality is indeed at index position 0 is "b", the position index 1 is nothing, is null
for two reasons: mark a thread A is executed after execution does not continue ensureCapacity (size + 1) In this case exactly equal minCapacity oldCapacity, B thread executed again, since the same minCapacity equal oldCapacity, ArrayList and not increasing the length, B the thread may continue to execute the assignment (elementData [size] = e) and size ++ also performed at this time , the CPU performs assignment went a thread, since the size value added. 1, the maximum size value is greater than the length of ArrayList, thus giving rise to an array bounds exception. For example: ArrayList default array size is 10. Suppose now been added into the nine elements, size = 9. Perform the following steps:

  1. A thread executing the add function is ensureCapacityInternal(size + 1)to hang.
  2. Thread B started, find the need to check the array capacity expansion. Thus the "b" in the index for the position 9, and the size is incremented by one. At this time, size = 10.
  3. A thread is then performed, attempts to "a" in the position labeled 10 because size = 10. But because the array has not expansion, the biggest index was 9, it will throw an array bounds exception

 

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_40826106/article/details/86596068