gpt4 book ai didi

java - IndexOutOfBoundsException when list.remove run in 2 thread 同时(并发)

转载 作者:行者123 更新时间:2023-11-30 08:03:04 26 4
gpt4 key购买 nike

我在 main 方法中有一个列表,我想写两个线程来使用这个列表。有时我会在同步块(synchronized block)中捕获 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 循环中检查所有条件。

关于java - IndexOutOfBoundsException when list.remove run in 2 thread 同时(并发),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36483698/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com