Java~原始碼分析為什麼ArrayList是執行緒不安全的, 如何將其變為執行緒安全的

2020-09-28 13:00:48

ArrayList不是執行緒安全的,使用一個案例演示

  • 任務類
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-09-27
 * Time: 15:42
 */
//執行緒任務類
public class CollectionTask implements Runnable {

    private List<String> list;

    public CollectionTask(List<String> list) {
        this.list = list;
    }


    @Override
    public void run() {
        //在任務中插入名字
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        list.add(Thread.currentThread().getName());

    }
}

  • 測試類
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-09-27
 * Time: 15:41
 */
//測試類
public class ArrayListSafetyTest {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //list = Collections.synchronizedList(list);
        CollectionTask task = new CollectionTask(list);
        for (int i = 0; i < 50; i++) {
            new Thread(task).start();
        }
        //等待執行緒執行
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //遍歷連結串列
        for (String str : list
             ) {
            System.out.println(str);
        }


    }
}

結果分析

在這裡插入圖片描述

  • 問題就是遍歷連結串列出現null值, 我們看看原始碼分析一下這是為什麼
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //新增一次元素就會size++一次
        elementData[size++] = e;
        return true;
    }
  • 問題就出在size++上, 多個執行緒同時給一個位置新增元素, 導致size++了, 但是資料覆蓋了, 所以就會出現空的位置

需要執行緒安全怎麼辦?

  • 使用Collections.synchronizedList(list)或者Vector<>()
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-09-27
 * Time: 15:41
 */
//測試類
public class ArrayListSafetyTest {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //重點
        list = Collections.synchronizedList(list);
        CollectionTask task = new CollectionTask(list);
        for (int i = 0; i < 50; i++) {
            new Thread(task).start();
        }
        //等待執行緒執行
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //遍歷連結串列
        for (String str : list
             ) {
            System.out.println(str);
        }


    }
}

原始碼分析其為何安全?

在這裡插入圖片描述

  • 很簡單就是給加個一把鎖