[英]IndexOutOfBoundsException when list.remove run in 2 thread the same time(concurrently)
我在main方法中有一個列表,我想編寫兩個使用此列表的線程。 有時我在同步塊中捕獲IndexOutOfBoundsException(當線程調用remove方法時)。
主要方法:
public class PC {
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
new Costumer("c1", strings).start();
new Costumer("c2", strings).start();
new Producer("p1", strings).start();
new Producer("p2", strings).start();
new Producer("p3", strings).start();
new Producer("p4", strings).start();
}
}
服裝課:
class Costumer extends Thread {
List<String> strings;
public Costumer(String n, List<String> strings) {
super(n);
this.strings = strings;
}
@Override
public void run() {
while (true) {
synchronized (strings) {
try {
if (strings.isEmpty()) {
strings.wait();
}
strings.remove(0); // <- where exception is thrown
} catch (InterruptedException ex) {
}
}
}
}
}
生產者類別:
class Producer extends Thread {
List<String> strings;
public Producer(String n, List<String> strings) {
super(n);
this.strings = strings;
}
@Override
public void run() {
while (true) {
synchronized (strings) {
strings.add(String.valueOf(Math.random() * 1000));
if (strings.size() == 1) {
strings.notify();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
}
堆棧跟蹤:
Exception in thread "c2" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.remove(Unknown Source)
at Costumer.run(PC.java:40)
代碼中的問題是Costumer
類中的if測試,必須將其替換為while循環,否則您可能會遇到競爭條件問題。 實際上,假設我們有一個使用者正在等待被通知,我們有一個使用者正在等待對字符串的鎖定,而我們的生產者具有對字符串的鎖定,並添加了新的字符串並由於沒有更多的字符串而調用通知。 因此,一旦它釋放了鎖,就可以說等待鎖的使用者首先獲得了它(是的,不要忘記已經被通知的使用者仍然需要獲得鎖,而不必先獲得鎖),然后刪除一個String,然后第二個使用者(已由該使用者通知的使用者)將從strings.wait()
開始,並在不檢查是否為空的情況下調用strings.remove(0)
,然后您將獲得IndexOutOfBoundsException
。
換句話說,代碼應為:
@Override
public void run() {
while (true) {
synchronized (strings) {
try {
while (strings.isEmpty()) {
strings.wait();
}
strings.remove(0);
} catch (InterruptedException ex) {
}
}
}
}
無論如何,將您的條件包裝到while循環中是一個好習慣,以避免像這樣的怪異錯誤。 例如,您可以在ArrayBlockingQueue之類的類中檢查其完成方式,所有條件都在while循環中檢查。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.