Java 为什么ThreadPoolExecutor将BlockingQueue作为其参数?
我已尝试使用Java 为什么ThreadPoolExecutor将BlockingQueue作为其参数?,java,multithreading,Java,Multithreading,我已尝试使用 int poolSize = 2; int maxPoolSize = 3; ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2); 队列达到最大大小后,将开始抛出“RejectedExecutionException”。意味着我无法添加这些任务 那么,如果BlockingQueue缺少任务,它的作用是什么?意味着它为什么不等待 从BlockingQueue的定义来
int poolSize = 2;
int maxPoolSize = 3;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2);
队列达到最大大小后,将开始抛出“RejectedExecutionException”。意味着我无法添加这些任务
那么,如果BlockingQueue缺少任务,它的作用是什么?意味着它为什么不等待
从BlockingQueue的定义来看
另外支持等待队列的操作的队列
在检索元素时变为非空,并等待释放空间
在存储元素时在队列中变为可用
为什么我们不能使用linkedlist(正常的队列实现而不是阻塞队列)?您没有按照预期的方式使用阻塞队列 BlockingQueue用于实现。生产者线程通过阻塞方法将项目放入队列,而消费者线程通过阻塞方法从队列中获取项目
put()
take()
此模式完全断开生产者与消费者的连接,只是它们共享队列
尝试这样使用队列:让执行器运行一些作为生产者的线程和一些作为消费者的线程。出现问题的原因是您的任务队列太小,方法的文档说明了这一点:
在将来的某个时候执行给定的任务。任务可以在新线程或现有池线程中执行。如果由于此执行器已关闭或已达到其容量而无法提交任务执行,则该任务将由当前RejectedExecutionHandler处理
因此,第一个问题是您将队列大小设置为一个非常小的数字:
int poolSize = 2;
int maxPoolSize = 3;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2);
现在,来回答你的其他问题
那么,如果BlockingQueue缺少任务,它的作用是什么
BlockingQueue
的作用是完成生产者/消费者模式,如果它足够大,那么您不应该看到您遇到的问题。如上所述,您需要增加队列大小并捕获异常,然后重试执行任务
为什么我们不能选择linkedlist
链表既不是线程安全的,也不是阻塞的。生产者/消费者模式往往在阻塞队列中工作得最好
更新
请不要被以下陈述所冒犯,我故意使用更严格的语言来强调这样一个事实,即您的第一个假设永远不应该是您正在使用的库有问题(除非您自己编写了库,并且您知道其中存在特定问题)
现在让我们来解决这个问题:这里的问题不是ThreadPoolExecutor
或Java库。完全是您(错误地)使用了该库。Javmex有一个解释你所看到的确切情况的方法
填充队列的速度比清空队列的速度快,可能有几个原因:
正在添加要执行的任务的线程添加任务的速度太快
任务的执行时间太长
你的队伍太小了
上述3项的任意组合
还有很多其他的原因,但我认为以上是最常见的
我会给你一个警告,但这不能解决你(误用)图书馆的问题因此,在我们指责Java库之前,让我们看一个简明的示例,它演示了您遇到的确切问题。
更新2.0
以下是解决具体问题的几个其他问题:
阻塞队列主要用于使用者(池中的线程)。线程可以等待队列中的新任务可用,它们将被自动唤醒。简单的链表不能达到这一目的
在生产者端,默认行为是在队列已满的情况下引发异常。这可以通过实现您自己的定制来轻松定制。在处理程序中,您可以控制队列并调用put方法,该方法将阻塞,直到有更多可用空间为止
但这并不是一件好事——原因是,如果这个执行器出现问题(死锁、处理速度慢),就会对系统的其余部分造成连锁反应。例如,如果您正在从servlet调用execute方法——如果execute方法阻塞,那么所有容器线程都将被阻塞,应用程序将停止。这可能就是为什么默认行为是抛出异常而不是等待。此外,还没有实现RejectedExceptionHandler来阻止人们使用它
在调用线程中有一个要执行的选项(),如果希望进行处理,它可以是另一个选项
一般规则是——最好是处理一个请求失败,而不是使整个系统崩溃。您可能想了解该模式。您可以找到阻塞队列的目的
/**
*用于保存任务并将其交给工作人员的队列
*线程。我们不要求workQueue.poll()返回
*null必然意味着workQueue.isEmpty(),因此依赖
*我想看看队列是否为空(我们必须这样做)
*例如,在决定是否从
*关闭以进行清理)。这适用于特殊用途
*允许轮询()的队列,如DelayQueues
*返回null,即使以后可能会返回
int poolSize = 2;
int maxPoolSize = 3;
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(2);
public void ExecuteTask(MyRunnableTask task) {
bool taskAdded = false;
while(!taskAdded) {
try {
executor.execute(task);
taskAdded = true;
} catch (RejectedExecutionException ex) {
taskAdded = false;
}
}
}
/**
* The queue used for holding tasks and handing off to worker
* threads. We do not require that workQueue.poll() returning
* null necessarily means that workQueue.isEmpty(), so rely
* solely on isEmpty to see if the queue is empty (which we must
* do for example when deciding whether to transition from
* SHUTDOWN to TIDYING). This accommodates special-purpose
* queues such as DelayQueues for which poll() is allowed to
* return null even if it may later return non-null when delays
* expire.
*/
private final BlockingQueue<Runnable> workQueue;
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
/**
* Performs blocking or timed wait for a task, depending on
* current configuration settings, or returns null if this worker
* must exit because of any of:
* 1. There are more than maximumPoolSize workers (due to
* a call to setMaximumPoolSize).
* 2. The pool is stopped.
* 3. The pool is shutdown and the queue is empty.
* 4. This worker timed out waiting for a task, and timed-out
* workers are subject to termination (that is,
* {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
* both before and after the timed wait, and if the queue is
* non-empty, this worker is not the last thread in the pool.
*
* @return task, or null if the worker must exit, in which case
* workerCount is decremented
*/
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // <---- wait at most keepAliveTime
workQueue.take(); // <---- if there are no tasks, it awaits on notEmpty.await();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}