Java 8中多執行緒對ArrayList 進行添加元素的時候,有概率某個位置會出現null值,也可能缺少元素,我覺得應該是擴容那塊出現問題,
public class ThreadTestArrayList {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(500);
LatchDemo ld = new LatchDemo(latch);
for (int i = 0; i < 500; i++) {
new Thread(ld).start();
}
latch.await();
ld.prif();
}
}
class LatchDemo implements Runnable {
public CountDownLatch latch;
public List<Integer> list = new ArrayList<>();
public LatchDemo(CountDownLatch latch) {
this.latch = latch;
}
@Override
public void run() {
// synchronized (this){
try {
list.add(0);
} finally {
latch.countDown();
}
//}
}
public void prif() {
System.out.println(list);
System.out.println(list.size());
}
}
CountDownLatch 這個是JUC里面的閉鎖,這里的意思就是讓main執行緒等待,讓其他執行緒先執行add完畢后,main執行緒再執行列印,不然輸出就不會準確,結果如下:

- 少元素的原因,可能是同一個陣列位置被覆寫了,因為size++并不是原子性的,所以可能執行緒A自增的時候,A的cpu時間片用完了,然后執行緒B也進行一次自增,導致A的自增被覆寫了,所以先完成的執行緒更新的資料會被后完成的執行緒覆寫掉,
- 出現null的原因,Java8中,直接new ArrayList<>()實體化的時候,底層的陣列是空的,大小為0,也就是第一次add會進行擴容的,假設現在有執行緒A和B分別要插入元素1和2,執行緒A呼叫add方法時,會進行它自己的擴容,在自己的作業空間創建新陣列,這時A擴容未完成呢,此時執行緒B呼叫add方法時發現也需要,這時B也會進行擴容也創建自己的陣列==(重點:這里都是在自己空間創建陣列)==,假設此時執行緒A比執行緒B擴容先完成,此時list的elementDate是新的陣列(A構建的),接著執行賦值操作elementDate[size++] = 1,在此之前執行緒B擴容 拿到的陣列仍然是舊的elementDate,于是執行緒B構造一個新的陣列(資料全部為null),然后使list的elementDate指向執行緒B構造的陣列,那么執行緒A之前的elementDate也就被丟掉了,但是由于size已經自增,所以執行緒B會在下一個位置賦予2,那么此時陣列元素就成了[null,2,x,x,x,x,x,x,x]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/282845.html
標籤:其他
