gpt4 book ai didi

java - ArrayBlockingQueue NoSuchElementException

转载 作者:太空宇宙 更新时间:2023-11-04 10:10:03 24 4
gpt4 key购买 nike

只是为了学习,我编写了以下用于自定义线程池的代码,引用并编辑显示的代码 here.

如代码所示,我使用 ArrayBlockingQueue 作为任务队列。

代码:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class ThreadPoolService {
private final BlockingQueue<Runnable> taskQueue;
private final int corePoolSize;

private ThreadPoolService(int corePoolSize) {
this.corePoolSize = corePoolSize;
this.taskQueue = new ArrayBlockingQueue<>(corePoolSize);
ThreadPool[] threadPool = new ThreadPool[corePoolSize];
for (int i = 0; i < corePoolSize; i++) {
threadPool[i] = new ThreadPool();
threadPool[i].start();
}
}

public static ThreadPoolService newFixedThreadPool(int size) {
return new ThreadPoolService(size);
}

public void execute(Runnable task) {
try {
taskQueue.offer(task, 10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

private class ThreadPool extends Thread {
Runnable task;

@Override
public void run() {
while (true) {
try {
while (!taskQueue.isEmpty()) {
task = taskQueue.remove();
task.run();
}
} catch (RuntimeException ex) {
ex.printStackTrace();
}
}
}
}

public static void main(String[] args) {
ThreadPoolService pool = ThreadPoolService.newFixedThreadPool(10);
Runnable task1 = () -> {
System.out.println(" Wait for sometime: -> " + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
};

Runnable task2 = () -> System.out.println(" Do Task 2 -> " + Thread.currentThread().getName());
Runnable task3 = () -> System.out.println(" Do Task 3 -> " + Thread.currentThread().getName());
Runnable task4 = () -> System.out.println(" Do Task 4 -> " + Thread.currentThread().getName());
List<Runnable> taskList = new ArrayList<>();
taskList.add(task1);
taskList.add(task2);
taskList.add(task3);
taskList.add(task4);
for (Runnable task : taskList) {
pool.execute(task);
}
}
}

此代码有时运行良好,有时会出错。

成功输出:

Do  Task 2 -> Thread-2
Wait for sometime: -> Thread-8
Do Task 3 -> Thread-6
Do Task 4 -> Thread-7

失败输出:

Do  Task 4 -> Thread-3
Do Task 3 -> Thread-6
Wait for sometime: -> Thread-4
Do Task 2 -> Thread-7
java.util.NoSuchElementException
at java.util.AbstractQueue.remove(AbstractQueue.java:117)
at com.interview.java.ThreadPoolService$ThreadPool.run(ThreadPoolService.java:43)
java.util.NoSuchElementException
at java.util.AbstractQueue.remove(AbstractQueue.java:117)
at com.interview.java.ThreadPoolService$ThreadPool.run(ThreadPoolService.java:43)
java.util.NoSuchElementException
at java.util.AbstractQueue.remove(AbstractQueue.java:117)
at com.interview.java.ThreadPoolService$ThreadPool.run(ThreadPoolService.java:43)

我发现错误的原因是在队列为空时尝试删除元素。但它不应该,因为我正在第 42 行进行队列空检查(while (!taskQueue.isEmpty()))。代码有什么问题以及为什么有时运行时没有错误?

最佳答案

在“while”检查和实际删除之间,队列可能会被另一个线程修改,可能会导致您提到的错误。这就是所谓的“竞争条件”。

因此,为了解决这个问题,您需要一种方法来阻止其他线程对队列的访问,可以通过“锁定”,或者使用带有共享锁对象的“同步” block 。或者简单地通过“轮询”而不是删除。

关于java - ArrayBlockingQueue NoSuchElementException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52463859/

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