每个人我对使用线程池有一个误解。实际结果与该类的API描述不同。当我在线程池中使用LinkedBlockedQueue
时,它不重用线程,线程池等待构造函数中设置的KeepAliveTime,然后杀死这个线程并创建一个新线程。当我将KeepAliveTime设置为较小值时,比如1秒或更短,它会删除一个线程并重新创建它,但如果我设置一分钟,则不会创建新线程,因为MaxPoolSize
不允许创建,队列已经满,所以所有任务都会被拒绝,但KeepAliveTime设置为分钟的线程这次什么也不做。我是个新手,不明白为什么它不重用这些线程。在keepTimeAlive
过期后,它将终止这些线程,如果队列已满,它将创建一个新线程。为什么会这样?据我从API了解,如果在keepAliveTime期间线程空闲,它必须重用它。当我使用SynchronousQueue
时,它会重用线程,而不是LinkedBlockingQueue
。
public class Main {
private volatile int remainingTasksCount;
private volatile static ThreadPoolExecutor consumer = new ThreadPoolExecutor(1, 2, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(3));
private static Runnable task = () -> {
System.out.println(String.format("consumer %s, id %s, size %s, active count %s, queue %s",
Thread.currentThread().getName(), Thread.currentThread().getId(),
consumer.getPoolSize(), consumer.getActiveCount(), 3-consumer.getQueue().remainingCapacity()));
String s = new String();
synchronized (s) {
try {
s.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) throws IOException {
try {
new Thread(() -> {
while (true) {
try {
for (int i = 0; i < 5; i++) {
consumer.submit(task);
}
System.out.println("PUSH TASKS");
synchronized (Thread.currentThread()) {
Thread.currentThread().wait(10000);
}
} catch (Throwable th) {
System.out.println(th);
}
}
}).start();
} catch (Throwable th) {
System.out.println(th);
}
}
输出
PUSH TASKS
consumer pool-1-thread-1, id 15, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 1
consumer pool-1-thread-1, id 15, size 2, active count 1, queue 2
consumer pool-1-thread-1, id 15, size 2, active count 1, queue 0
Disconnected from the target VM, address: '127.0.0.1:64434', transport: 'socket'
Process finished with exit code 1
但下次制作人提交任务时,我会收到RejectedExecutionException
如果我将保持AliveTime
更改为1秒
。一切正常,但会创建新线程。
PUSH TASKS
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 3
consumer pool-1-thread-1, id 15, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 2
consumer pool-1-thread-1, id 15, size 2, active count 2, queue 1
consumer pool-1-thread-2, id 16, size 2, active count 1, queue 0
PUSH TASKS
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 3
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 2
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 1
consumer pool-1-thread-2, id 16, size 2, active count 2, queue 1
consumer pool-1-thread-3, id 17, size 2, active count 1, queue 0
consumer pool-1-thread-3, id 17, size 1, active count 1, queue 2
PUSH TASKS
consumer pool-1-thread-4, id 18, size 2, active count 2, queue 3
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 1
consumer pool-1-thread-4, id 18, size 2, active count 2, queue 1
consumer pool-1-thread-3, id 17, size 2, active count 1, queue 0
PUSH TASKS
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 2
consumer pool-1-thread-5, id 19, size 2, active count 2, queue 3
consumer pool-1-thread-3, id 17, size 2, active count 2, queue 1
consumer pool-1-thread-5, id 19, size 2, active count 2, queue 1
consumer pool-1-thread-3, id 17, size 2, active count 1, queue 0
我会很高兴如果有人能解释我的错误或一些基本原则我错过了
由于您的代码示例,我认为您对线程池的工作方式有一些误解。我尝试运行它并从5个任务和无限数量的Reject tedExecutionException之后获得输出。发生这种情况是因为在异常的情况下Thread.currentThread(). etc(10000);
未被调用并且向池中添加了另外5个任务,并且此逻辑一次又一次地重复产生新的异常。尝试包围consumer.submit(任务);使用try-catch块,您会看到只有两个线程按预期处理所有任务,因为保持TimeAlive
比等待时间长。在第二个示例中,保持TimeAlive
比等待时间短,因此在每次等待之后都会创建新的非核心线程,并且您会在每次循环调用后看到不同的id。这是正确的,因为之前的非核心线程已停止,因为它的空闲时间比保持TimeAlive
长。
这是一个竞争条件。如果您遵循的提交()
足够长的时间(在源代码中),您将到达ThreadPoolExecutor.execucte()
:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/* long comment block removed */
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
当您的提交循环第一次运行时,执行将创建新的辅助角色,并为他们提供您的任务,而无需尝试将它们推入队列(addWorker
返回
),因此2个任务立即开始,3个进入可以容纳所有3个任务的队列。
第二次,submit
-s将以工作队列结束。提供
东西,这可能会使队列饱和(取决于工作人员尝试使用新物品的速度),当它达到饱和时,最后一次尝试添加工作人员将运行并失败,导致拒绝,因为不允许创建新工作人员。
实际上,如果你开始在提交循环中做“事情”,它最终会开始工作。例如,我试着println(I)
,这足够慢,可以消耗一些任务,循环成功。当我尝试打印(I)时,它已经太快了,在第4次提交时就消失了,所以没有任务很快被消耗掉。所以这是一个微妙的问题,通常情况下的种族条件是什么。
主要内容:1 什么是Java 线程池,2 Java 线程池的优势,3 Java 线程池的应用场景,4 Java 线程池的例子1 什么是Java 线程池 Java线程池 表示一组正在等待作业并多次重复使用的工作线程。 如果是线程池,则会创建一组固定大小的线程。服务提供商从线程池中拉出一个线程并为其分配作业。作业完成后,线程再次包含在线程池中。 2 Java 线程池的优势 由于无需创建新线程,因此拥有更好的性能,可以节省时间。 3 Java 线程池的应用场景 在用户请求Servlet和JSP时,其中
一、概述 在我们的开发中经常会使用到多线程。例如在Android中,由于主线程的诸多限制,像网络请求等一些耗时的操作我们必须在子线程中运行。我们往往会通过new Thread来开启一个子线程,待子线程操作完成以后通过Handler切换到主线程中运行。这么以来我们无法管理我们所创建的子线程,并且无限制的创建子线程,它们相互之间竞争,很有可能由于占用过多资源而导致死机或者OOM。所以在Java中为我们
主要内容:一、MySql中的线程,二、主要方式,三、源码流程,四、总结一、MySql中的线程 在mysql中,每一个连接上来,就会分配给一个相关的THD数据类。在前面的分析中可以看到,连接器(Connectors)连接到的直接就是连接池,在连接池的线程处理中分为三部分,即一对一(一个连接对应一个线程),多对一(多个连接对应一个线程)和线程池(多对多)。 线程池和线程可以针对不同的具体场景来处理具体的事务,这样既兼顾了效率又提高了适应性,对于新手来说,这就是设计的一个
我刚刚开始研究Java的类和方法。根据API,生成的线程池重用现有的对象来执行新任务。 我有点困惑这是如何实现的,因为我在API中找不到任何方法可以设置现有对象的行为。 例如,可以从对象创建新的,这使得调用的方法。但是,API中没有将作为参数的setter方法。 我会很感激你的指点。
接收到数据时回调此函数,发生在worker进程中。函数原型: function onReceive(swoole_server $server, int $fd, int $reactor_id, string $data); $server,swoole_server对象 $fd,TCP客户端连接的唯一标识符 $reactor_id,TCP连接所在的Reactor线程ID $data,收到的数
本文向大家介绍Java 线程池详解,包括了Java 线程池详解的使用技巧和注意事项,需要的朋友参考一下 系统启动一个线程的成本是比较高的,因为它涉及到与操作系统的交互,使用线程池的好处是提高性能,当系统中包含大量并发的线程时,会导致系统性能剧烈下降,甚至导致JVM崩溃,而线程池的最大线程数参数可以控制系统中并发线程数不超过次数。 一、Executors 工厂类用来产生线程池,该工厂类包含以下几个静