Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/344.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么ThreadPoolExecutor将BlockingQueue作为其参数?_Java_Multithreading - Fatal编程技术网

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;
                }
            }
        }