摘要:源碼和多線程安全問題分析在分析線程安全問題之前,我們線對此類的源碼進行分析,找出可能出現(xiàn)線程安全問題的地方,然后代碼進行驗證和分析。即當(dāng)多線程調(diào)用方法的時候會出現(xiàn)元素覆蓋的問題。
1.ArrayList源碼和多線程安全問題分析
在分析ArrayList線程安全問題之前,我們線對此類的源碼進行分析,找出可能出現(xiàn)線程安全問題的地方,然后代碼進行驗證和分析。
1.1 數(shù)據(jù)結(jié)構(gòu)ArrayList內(nèi)部是使用數(shù)組保存元素的,數(shù)據(jù)定義如下:
transient Object[] elementData; // non-private to simplify nested class access
在ArrayList中此數(shù)組即是共享資源,當(dāng)多線程對此數(shù)據(jù)進行操作的時候如果不進行同步控制,即有可能會出現(xiàn)線程安全問題。
1.2 add方法可能出現(xiàn)的問題分析首先我們看一下add的源碼如下:
public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; return true; }
此方法中有兩個操作,一個是數(shù)組容量檢查,另外就是將元素放入數(shù)據(jù)中。我們先看第二個簡單的開始分析,當(dāng)多個線程執(zhí)行順序如下所示的時候,會出現(xiàn)最終數(shù)據(jù)元素個數(shù)小于期望值。
按照此順序執(zhí)行完之后,我們可以看到,elementData[n]的只被設(shè)置了兩次,第二個線程設(shè)置的值將前一個覆蓋,最后size=n+1。下面使用代碼進行驗證此問題。
1.3 代碼驗證首先先看下以下代碼,開啟1000個線程,同時調(diào)用ArrayList的add方法,每個線程向ArrayList中添加100個數(shù)字,如果程序正常執(zhí)行的情況下應(yīng)該是輸出:
list size is :10000
代碼如下:
private static Listlist = new ArrayList (); 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()); }
當(dāng)執(zhí)行此main方法后,輸出如下:
從以上執(zhí)行結(jié)果來看,最后輸出的結(jié)果會小于我們的期望值。即當(dāng)多線程調(diào)用add方法的時候會出現(xiàn)元素覆蓋的問題。
1.4 數(shù)組容量檢測的并發(fā)問題在add方法源碼中,我們看到在每次添加元素之前都會有一次數(shù)組容量的檢測,add中調(diào)用此方法的源碼如下:
ensureCapacityInternal(size + 1);
容量檢測的相關(guān)源碼如下:
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); }
容量檢測的流程圖如下所示:
我們以兩個線程執(zhí)行add操作來分析擴充容量可能會出現(xiàn)的并發(fā)問題:
當(dāng)我們新建一個ArrayList時候,此時內(nèi)部數(shù)組容器的容量為默認(rèn)容量10,當(dāng)我們用兩個線程同時添加第10個元素的時候,如果出現(xiàn)以下執(zhí)行順序,可能會拋出java.lang.ArrayIndexOutOfBoundsException異常。
第二個線程往數(shù)組中添加數(shù)據(jù)的時候由于數(shù)組容量為10,而此操作往index為10的位置設(shè)置元素值,因此會拋出數(shù)組越界異常。
1.5 代碼驗證數(shù)組容量檢測的并發(fā)問題使用如下代碼:
private static Listlist = new ArrayList (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(); }
執(zhí)行main方法后,我們可以看到控制臺輸出如下:
ArrayList中其他包含對共享變量操作的方法同樣會有并發(fā)安全問題,只需要按照以上的分析方法分析即可。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/67638.html
摘要:今天主要講解的是本文力求簡單講清每個知識點,希望大家看完能有所收獲一和回顧線程安全的和我們知道是用于替代的,是線程安全的容器。使用迭代器遍歷時不需要顯示加鎖,看看與方法的實現(xiàn)可能就有點眉目了。 前言 只有光頭才能變強 showImg(https://segmentfault.com/img/remote/1460000016931828?w=1120&h=640); 前一陣子寫過一篇C...
摘要:常用集合使用場景分析過年前的最后一篇,本章通過介紹,,,底層實現(xiàn)原理和四個集合的區(qū)別。和都是線程安全的,不同的是前者使用類,后者使用關(guān)鍵字。面試官會認(rèn)為你是一個基礎(chǔ)扎實,內(nèi)功深厚的人才到這里常用集合使用場景分析就結(jié)束了。 Java 常用List集合使用場景分析 過年前的最后一篇,本章通過介紹ArrayList,LinkedList,Vector,CopyOnWriteArrayList...
摘要:而且只要他更新完畢對修飾的變量賦值,那么讀線程立馬可以看到最新修改后的數(shù)組,這是保證的。這個時候,就采用了思想來實現(xiàn)這個,避免更新的時候阻塞住高頻的讀操作,實現(xiàn)無鎖的效果,優(yōu)化線程并發(fā)的性能。 今天聊一個非常硬核的技術(shù)知識,給大家分析一下CopyOnWrite思想是什么,以及在Java并發(fā)包中的具體體現(xiàn),包括在Kafka內(nèi)核源碼中是如何運用這個思想來優(yōu)化并發(fā)性能的。這個CopyOnW...
摘要:學(xué)習(xí)編程的本最佳書籍這些書涵蓋了各個領(lǐng)域,包括核心基礎(chǔ)知識,集合框架,多線程和并發(fā),內(nèi)部和性能調(diào)優(yōu),設(shè)計模式等。擅長解釋錯誤及錯誤的原因以及如何解決簡而言之,這是學(xué)習(xí)中并發(fā)和多線程的最佳書籍之一。 showImg(https://segmentfault.com/img/remote/1460000018913016); 來源 | 愿碼(ChainDesk.CN)內(nèi)容編輯 愿碼Slo...
閱讀 3319·2021-11-08 13:12
閱讀 2756·2021-10-15 09:41
閱讀 1451·2021-10-08 10:05
閱讀 3300·2021-10-08 10:04
閱讀 2102·2021-09-29 09:34
閱讀 2472·2019-08-30 15:55
閱讀 2979·2019-08-30 15:45
閱讀 2577·2019-08-29 14:17