2013-10-27 37 views
0

我正在閱讀Java Concurrency in Practice,根據其中的一些java代碼,System.out.println()將導致ConcurrentModificationException。代碼如下:爲什麼在使用System.out.println()打印一個集合時發生concurrentmodificationexception?

private final Set<Integer> set = new HashSet<Integer>(); 

public synchronized void add(Integer i) {set.add(i); } 

public synchronized void remove(Integer i) {set.remove(i);} 

public void addTenThings() { 

    Random r = new Random(); 
    for (int i = 0; i < 10; i++) { 
     add(r.nextInt()); 
    } 

    System.out.println("DEBUG: add ten elements to " + set); 
} 

由於System.out.println()方法只會調用toString方法:

public String toString() { 
    Iterator<E> i = iterator(); 
if (! i.hasNext()) 
    return "[]"; 

StringBuilder sb = new StringBuilder(); 
sb.append('['); 
for (;;) { 
    E e = i.next(); 
    sb.append(e == this ? "(this Collection)" : e); 
    if (! i.hasNext()) 
    return sb.append(']').toString(); 
    sb.append(", "); 
} 
} 

我仍然無法理解爲什麼ConcurrentModificationException被扔?

+0

您正在迭代集合,而另一個線程可能正在修改它。你的''+ set'調用'set'對象的toString() –

回答

1

假設2個線程 - AB同時執行方法addTenThings()。他們可以這樣做,因爲方法不同步。

然後,如果在該線程A正在執行的toString()方法set,從而遍歷它,線程B仍在執行循環,並調用add()方法的時間,這可能會導致ConcurrentModificationException,因爲兩個線程正在操作只在同一set。沒有什麼能夠阻止線程執行add(r.nextInt())語句,而另一個線程正在執行方法中的print語句。

+0

我按照你所說的爲服務器時間做了這個,但沒有發生,我錯過了什麼? – znlyj

+0

@znlyj如上所述,代碼**可能**拋出異常 –

+0

@znlyj你可以做到十億次,並且在一臺機器上看不到這個bug,但是當你在不同的機器上運行JVM版本或OS時,你可能會一直看到它。一個線程可以在另一個線程啓動之前運行完畢 –

相關問題