[英]Java, adding elements in an array an concurrently looping through it
抱歉,這是一個愚蠢的問題。 但是有人可以解釋我在這種情況下會發生什么嗎?
List<Integer> scores = new Arraylist<>() ;
scores =
Collections.synchronizedList(scores)
public void add(int element) {
...
scores.add(element)
...
}
public String retrieve(int element) {
...
For (Integer e : scores)....
....
Return something
}
讓我們假設這個類是單例,得分是全局的。 多線程可以同時添加和檢索分數
在這種情況下,當啟動for循環並同時添加線程(或從列表中刪除元素)時,它將引發並發修改示例嗎?
謝謝
考慮到您編寫示例的方式,壞事將會發生。
您的retrieve()
方法沒有在synchronized
塊中循環,並且您的兩個方法都直接訪問scores
,而不是使用Collections.synchronizedList()
方法返回的List
。
如果您查看Collections.synchronizedList()
的API,您會注意到它說
為了保證串行訪問,至關重要的是,對后備列表的所有訪問都必須通過返回的列表來完成。
當用戶遍歷返回列表時,必須手動對其進行同步:
不遵循此建議可能導致不確定的行為。
因此,您可能會收到ConcurrentModificationException
,否則可能會發生其他奇怪的事情。
即使您所有的訪問都是通過同步的List
,但是如果在另一個線程中迭代List
時修改List
,仍然可能最終拋出ConcurrentModificationException
。 這就是為什么Collections.synchronizedList()
文檔堅持要求您手動將迭代包裝在與返回的List
同步的塊中的原因。
用於ConcurrentModificationException的API說
例如, 通常不允許一個線程修改Collection,而另一個線程對其進行迭代 。 通常,在這些情況下,迭代的結果是不確定的。 如果檢測到此行為,則某些Iterator實現(包括JRE提供的所有通用集合實現的實現) 可能會選擇拋出此異常 。 執行此操作的迭代器稱為快速失敗迭代器,因為它們會快速干凈地失敗,而不是在未來的不確定時間內冒任意,不確定的行為的風險。
您的add方法不需要更改,但是您的retrieve()
方法應類似於:
public String retrieve(int element) {
// stuff
synchronized (scores) { // prevent scores from being modified while iterating
for (Integer e : scores) {
// looping stuff
}
}
// more stuff
return something;
}
這是一個小示例程序,演示了安全訪問與不安全訪問的行為:
public class Scratch {
private List<Integer> scores = Collections.synchronizedList(new ArrayList<Integer>());
public static void main(String[] args) throws Exception {
final Scratch s = new Scratch();
s.scores.add(1);
s.scores.add(2);
s.scores.add(3);
// keep adding things to the list forever
new Thread(new Runnable() {
@Override
public void run() {
try {
int i=100;
while (true) {
Thread.sleep(100);
s.scores.add(i++);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out.println("This will run fine");
s.safeLoop();
System.out.println("This will cause a ConcurrentModificationException");
s.unsafeLoop();
}
public void safeLoop() throws InterruptedException {
synchronized (scores) {
for (int i : scores) {
System.out.println("i="+i);
Thread.sleep(100);
}
}
}
public void unsafeLoop() throws InterruptedException {
for (int i : scores) {
System.out.println("i="+i);
Thread.sleep(100);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.