中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

ArrayList源碼和多線程安全問題分析

發布時間:2020-09-03 14:50:18 來源:腳本之家 閱讀:213 作者:NULL 欄目:編程語言

1.ArrayList源碼和多線程安全問題分析

在分析ArrayList線程安全問題之前,我們線對此類的源碼進行分析,找出可能出現線程安全問題的地方,然后代碼進行驗證和分析。

1.1 數據結構

ArrayList內部是使用數組保存元素的,數據定義如下:

transient Object[] elementData; // non-private to simplify nested class access

在ArrayList中此數組即是共享資源,當多線程對此數據進行操作的時候如果不進行同步控制,即有可能會出現線程安全問題。

1.2 add方法可能出現的問題分析

首先我們看一下add的源碼如下:

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

此方法中有兩個操作,一個是數組容量檢查,另外就是將元素放入數據中。我們先看第二個簡單的開始分析,當多個線程執行順序如下所示的時候,會出現最終數據元素個數小于期望值。

ArrayList源碼和多線程安全問題分析

按照此順序執行完之后,我們可以看到,elementData[n]的只被設置了兩次,第二個線程設置的值將前一個覆蓋,最后size=n+1。下面使用代碼進行驗證此問題。

1.3 代碼驗證

首先先看下以下代碼,開啟1000個線程,同時調用ArrayList的add方法,每個線程向ArrayList中添加100個數字,如果程序正常執行的情況下應該是輸出:

list size is :10000

代碼如下:

private static List<Integer> list = new ArrayList<Integer>();
private static ExecutorService executorService = Executors.newFixedThreadPool(1000);
private static class IncreaseTask extends Thread{
@Override
public void run() {
System.out.println("ThreadId:" + Thread.currentThread().getId() + " start!");
for(int i =0; i < 100; i++){
list.add(i);
}
System.out.println("ThreadId:" + Thread.currentThread().getId() + " finished!");
}
}
public static void main(String[] args){
for(int i=0; i < 1000; i++){
executorService.submit(new IncreaseTask());
}
executorService.shutdown();
while (!executorService.isTerminated()){
try {
Thread.sleep(1000*10);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("All task finished!");
System.out.println("list size is :" + list.size());
}

當執行此main方法后,輸出如下:

ArrayList源碼和多線程安全問題分析

從以上執行結果來看,最后輸出的結果會小于我們的期望值。即當多線程調用add方法的時候會出現元素覆蓋的問題。

1.4 數組容量檢測的并發問題

在add方法源碼中,我們看到在每次添加元素之前都會有一次數組容量的檢測,add中調用此方法的源碼如下:

ensureCapacityInternal(size + 1);

容量檢測的相關源碼如下:

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

容量檢測的流程圖如下所示:

ArrayList源碼和多線程安全問題分析

我們以兩個線程執行add操作來分析擴充容量可能會出現的并發問題:
當我們新建一個ArrayList時候,此時內部數組容器的容量為默認容量10,當我們用兩個線程同時添加第10個元素的時候,如果出現以下執行順序,可能會拋出java.lang.ArrayIndexOutOfBoundsException異常。

ArrayList源碼和多線程安全問題分析

第二個線程往數組中添加數據的時候由于數組容量為10,而此操作往index為10的位置設置元素值,因此會拋出數組越界異常。

1.5 代碼驗證數組容量檢測的并發問題

使用如下代碼:

private static List<Integer> list = new ArrayList<Integer>(3);
private static ExecutorService executorService = Executors.newFixedThreadPool(10000);
private static class IncreaseTask extends Thread{
@Override
public void run() {
System.out.println("ThreadId:" + Thread.currentThread().getId() + " start!");
for(int i =0; i < 1000000; i++){
list.add(i);
}
System.out.println("ThreadId:" + Thread.currentThread().getId() + " finished!");
}
}
public static void main(String[] args){
new IncreaseTask().start();
new IncreaseTask().start();
}

執行main方法后,我們可以看到控制臺輸出如下:

ArrayList源碼和多線程安全問題分析

1.6 ArrayList中其他方法說明

ArrayList中其他包含對共享變量操作的方法同樣會有并發安全問題,只需要按照以上的分析方法分析即可。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

崇州市| 莆田市| 叙永县| 房山区| 定结县| 凤庆县| 驻马店市| 安庆市| 唐山市| 鄂托克前旗| 蚌埠市| 留坝县| 莒南县| 开原市| 安乡县| 浪卡子县| 大庆市| 岚皋县| 阿克陶县| 项城市| 罗山县| 安塞县| 泗洪县| 红原县| 梓潼县| 吴川市| 平果县| 左权县| 文成县| 图们市| 乐昌市| 松江区| 旬邑县| 开阳县| 无锡市| 安溪县| 福海县| 樟树市| 大同市| 安远县| 宁武县|