gpt4 book ai didi

java - ArrayList方法导致Producer Consumer死锁

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

这是 Java 中的生产者消费者场景。生产者在 ArrayList 中写入,而消费者正在从中读取。两者都在添加或删除元素之前锁定 ArrayList 对象。

在 Consumer 类中,在打印列表中的最后一个元素之前,在 ArrayList 上调用了 remove 方法,这是一种错误。但是你能帮我理解为什么会导致死锁吗?

如果我在 System.out.println(...) 之后放置 remove 调用,它会很好地工作(无限生产者和消费者都可以工作)。

下面是我正在谈论的 Consumer 中的 2 行

buffer.remove(buffer.size()-1);
System.out.println("Consumed" + " " + buffer.get(buffer.size() - 1) + " size " + buffer.size());

完整代码:

public class Test {

public static void main(String[] args) {

ArrayList<Integer> arrayList = new ArrayList<>(10);

Producer producer = new Producer(arrayList);
Consumer consumer = new Consumer(arrayList);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(producer);
executorService.submit(consumer);
}
}
class Producer implements Runnable{

private final ArrayList<Integer> buffer;
public Producer(ArrayList<Integer> arrayList){
this.buffer = arrayList;
}

public void run(){
while (true) {
synchronized (buffer) {
while (isFull(buffer)) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer.add(1);
System.out.println("Produced" + " " + buffer.get(buffer.size() - 1) + " size " + buffer.size());
buffer.notifyAll();
}
}
}

private boolean isFull(ArrayList<Integer> buffer) {
return buffer.size() == 10;
}
}
class Consumer implements Runnable{

private final ArrayList<Integer> buffer;

public Consumer(ArrayList<Integer> buffer) {
this.buffer = buffer;
}

public void run(){
while (true) {
synchronized (buffer) {
while (isEmpty(buffer)) {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer.remove(buffer.size()-1);
System.out.println("Consumed" + " " + buffer.get(buffer.size() - 1) + " size " + buffer.size());
buffer.notifyAll();
}
}
}

private boolean isEmpty(ArrayList<Integer> buffer) {
return buffer.size() == 0;
}
}

发生死锁时的典型输出,在生产者释放锁之后消费者线程不会开始处理。

Produced 1 size 1
Produced 1 size 2
Produced 1 size 3
Produced 1 size 4
Produced 1 size 5
Produced 1 size 6
Produced 1 size 7
Produced 1 size 8
Produced 1 size 9
Produced 1 size 10
Consumed 1 size 9
Consumed 1 size 8
Consumed 1 size 7
Consumed 1 size 6
Consumed 1 size 5
Consumed 1 size 4
Consumed 1 size 3
Consumed 1 size 2
Consumed 1 size 1
Produced 1 size 1
Produced 1 size 2
Produced 1 size 3
Produced 1 size 4
Produced 1 size 5
Produced 1 size 6
Produced 1 size 7
Produced 1 size 8
Produced 1 size 9
Produced 1 size 10

JDK : jdk1.8.0_111

下面是生产者和消费者线程的线程转储

"pool-1-thread-2" #11 prio=5 os_prio=31 tid=0x00007fb1e8039800 nid=0x3c03 waiting on condition [0x000070000fa72000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000007aac942a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

"pool-1-thread-1" #10 prio=5 os_prio=31 tid=0x00007fb1e704d800 nid=0x3b03 in Object.wait() [0x000070000f96f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007aac8a998> (a java.util.ArrayList)
at java.lang.Object.wait(Object.java:502)
at com.vipin.threading.Producer.run(Test.java:36)
- locked <0x00000007aac8a998> (a java.util.ArrayList)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

修复很简单,正如我在上面解释的那样,它在更改 remove 和 sysout 的顺序后起作用,我正在寻找它导致死锁的原因的解释。

最佳答案

buffer.get(buffer.size() - 1) 当列表为空时抛出异常。

您可以使用 Future.get 了解此异常:

try {
executorService.submit(consumer).get();
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}

关于java - ArrayList方法导致Producer Consumer死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51909776/

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