對list的執行緒不安全操作
阿新 • • 發佈:2019-02-17
對一個執行緒不安全的集合進行多執行緒操作, 並不會破單個元素的完整性, 根據java記憶體模型可知,
public class TestCl { List<Integer> no = Collections.synchronizedList(new ArrayList<>()); //List<Integer> no = new ArrayList<>(); public static void main(String[] args) throws InterruptedException { TestCl t = new TestCl(); for(int i=0;i<10000;i++) { new Thread(t.new InnerThread(i)).start(); } TimeUnit.SECONDS.sleep(10); System.out.println(t.no.size()); } public class InnerThread implements Runnable{ Integer i; public InnerThread (Integer i) { this.i = i; } @Override public void run() { // TODO Auto-generated method stub no.add(i); } } }
對於同步的list, 輸出結果是10000
對於非同步的list, 輸出結果會小於10000, 因為arraylist存在兩個全域性變數transient Object[] elementData; private int size; 而在多執行緒執行add方法時, 兩個全域性變數會出現執行緒安全問題. 當兩個執行緒同時操作兩個全域性變數, 如果其中一個執行緒沒有及時將當前快取的內容重新整理到共享記憶體中, 這個執行緒最後重新整理的時候可能會覆蓋其他已經修改的該位置的內容public class TestCl { //List<Integer> no = Collections.synchronizedList(new ArrayList<>()); List<Integer> no = new ArrayList<>(); public static void main(String[] args) throws InterruptedException { TestCl t = new TestCl(); for(int i=0;i<10000;i++) { new Thread(t.new InnerThread(i)).start(); } TimeUnit.SECONDS.sleep(10); System.out.println(t.no.size()); } public class InnerThread implements Runnable{ Integer i; public InnerThread (Integer i) { this.i = i; } @Override public void run() { // TODO Auto-generated method stub no.add(i); } } }
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }