準備試驗樣本
實現樣本
/**
* 兩個線程都過了數組大小檢查,先後插入數據時 引起 out of bound
* @author Geym
*
*/
public class UnsafeArrayList {
static ArrayList al=new ArrayList();
static class AddTask implements Runnable{
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
for(int i=0;i<1000000;i++)
al.add(new Object());
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(new AddTask(),"t1");
Thread t2=new Thread(new AddTask(),"t2");
t1.start();
t2.start();
Thread t3=new Thread(new Runnable(){
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
}
}
},"t3");
t3.start();
}
}
ArrayList在多線程訪問情況下會出現異常`java.lang.ArrayIndexOutOfBoundsException: 11`
正式起航
ArrayList內部add()內部設置斷點.
debug模式啓動,進入斷點,顯示完整堆棧,但顯示的是主線程的堆棧信息
設置斷點屬性,使得只讓t1和t2線程進入斷點
掛起整個虛擬機
掛起虛擬機而不是掛起線程
調試進入ArrayList內部
ArrayList的工作方式:
Arraylist內部初始化爲10個數組空間,當數組空間消耗完畢後,arraylist就會自動擴容.在每次add()函數時,系統總要事先檢查下內部空間是否滿足所需的大小.
多線程情況下,當arraylist容量快用完時,兩個線程同時進入add()函數,並同時認爲不需要擴容,且各自寫入自己的數據,那麼很可能有一個線程會將數據寫到邊界外,從而產生ArrayIndexOutOfBoundsException.
設置斷點,模擬到達線程擴容臨界點9:
t1和t2線程均進入方法:
t1線程執行到下一步,切換t2線程:
t2線程執行到下一步,切換回t1線程進行添加元素:
t2線程拋出異常,ArrayIndexOutOfBoundsException: