配置如下:
new ThreadPoolExecutor(10, 100, 30, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(100))
那么一旦有 10 个线程同时处理请求,就将进一步的请求添加到队列中,除非队列中达到 100 个请求,此时会开始创建新的线程,除非已经有 100 个线程,此时该命令的处理将被拒绝。
(复制如下)的javadocsThreadPoolExecutor
部分可能值得一读。
基于它们,以及您显然愿意运行 100 个线程,以及您希望接受所有请求并最终处理它们。我建议尝试以下变体:
new ThreadPoolExecutor(100, 100, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>())
顺便说一句,这就是你从中得到的Executors.newFixedThreadPool(100);
排队
任何 BlockingQueue 都可以用来传输和保存提交的任务。此队列的使用与池大小交互:
- 如果运行的线程少于 corePoolSize,则 Executor 总是更喜欢添加新线程而不是排队。
- 如果 corePoolSize 或更多线程正在运行,Executor 总是更喜欢排队请求而不是添加新线程。
- 如果请求无法排队,则会创建一个新线程,除非这将超过 maximumPoolSize,在这种情况下,该任务将被拒绝。
排队的一般策略有以下三种:
- 直接交接。工作队列的一个很好的默认选择是 SynchronousQueue,它将任务交给线程而不用其他方式保留它们。在这里,如果没有立即可用的线程来运行任务,则尝试将任务排队将失败,因此将构造一个新线程。在处理可能具有内部依赖关系的请求集时,此策略可避免锁定。直接切换通常需要无限的 maximumPoolSizes 以避免拒绝新提交的任务。这反过来又承认了当命令的平均到达速度超过了它们的处理速度时,可能会出现无限线程增长。
- 无界队列。当所有 corePoolSize 线程都忙时,使用无界队列(例如没有预定义容量的 LinkedBlockingQueue)将导致新任务在队列中等待。因此,不会创建超过 corePoolSize 个线程。(因此maximumPoolSize的值没有任何影响。)当每个任务完全独立于其他任务时,这可能是合适的,因此任务不会影响彼此的执行;例如,在网页服务器中。虽然这种排队方式在平滑请求的瞬时突发方面很有用,但它承认当命令平均到达速度快于处理速度时,工作队列可能会无限增长。
- Bounded queues. A bounded queue (for example, an ArrayBlockingQueue) helps prevent resource exhaustion when used with finite maximumPoolSizes, but can be more difficult to tune and control. Queue sizes and maximum pool sizes may be traded off for each other: Using large queues and small pools minimizes CPU usage, OS resources, and context-switching overhead, but can lead to artificially low throughput. If tasks frequently block (for example if they are I/O bound), a system may be able to schedule time for more threads than you otherwise allow. Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.