在Java ThreadPoolExecutor中在运行时更改线程池大小
我是核心Java编程新手,目前正在从事一个与多线程相关的项目 我们有一个多客户端调用的异步服务。每个客户机都有一个单独的使用者,它使用为客户机分配的固定数量的线程来消费和处理队列中的请求。现在的问题是,一些客户在一周内发送大量流量,而一些客户在周末发送。 e、 客户机1在工作日每秒发送900个请求,而在周末仅发送200个请求。另一方面,客户端2在工作日发送100个,但在周末发送1000多个 因此,我们需要在不重新启动服务的情况下实时更新每个客户端的线程分配。根据我的理解,setCorePoolSize会自动覆盖池大小并停止空闲线程。但在我们的设置中,我们确保下一个任务总是在线程开始执行当前任务之前提交给线程。所以线程永远不会空闲,减少池大小可能是个问题 我看到了几篇关于在执行之前或之后中断线程的帖子,我尝试使用CountDownLatch编写代码片段: DynamicThreadPool类:在Java ThreadPoolExecutor中在运行时更改线程池大小,java,multithreading,threadpoolexecutor,countdownlatch,Java,Multithreading,Threadpoolexecutor,Countdownlatch,我是核心Java编程新手,目前正在从事一个与多线程相关的项目 我们有一个多客户端调用的异步服务。每个客户机都有一个单独的使用者,它使用为客户机分配的固定数量的线程来消费和处理队列中的请求。现在的问题是,一些客户在一周内发送大量流量,而一些客户在周末发送。 e、 客户机1在工作日每秒发送900个请求,而在周末仅发送200个请求。另一方面,客户端2在工作日发送100个,但在周末发送1000多个 因此,我们需要在不重新启动服务的情况下实时更新每个客户端的线程分配。根据我的理解,setCorePoolS
public class DynamicThreadPool extends ThreadPoolExecutor {
private int currentThreadCount;
private AtomicReference<CountDownLatch> executeLatch;
public DynamicThreadPool(int nThreads) {
super(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
currentThreadCount = nThreads;
executeLatch = new AtomicReference<>(new CountDownLatch(0));
}
@Override
public void beforeExecute(Thread t, Runnable r)
{
super.beforeExecute(t, r);
try {
executeLatch.get().await();
} catch (final InterruptedException e) {
t.interrupt();
}
}
public void resize(int nThreads) {
if (currentThreadCount == nThreads) {
return;
}
try {
executeLatch.getAndSet(new CountDownLatch(1));
currentThreadCount = nThreads;
setCorePoolSize(nThreads);
setMaximumPoolSize(nThreads);
prestartAllCoreThreads();
executeLatch.get().countDown();
}
catch (Exception e) {
log.warn("resizer caught exception");
}
}
}
公共类DynamicThreadPool扩展ThreadPoolExecutor{
私有int currentThreadCount;
私有原子引用执行器;
公共动态线程池(int-nThreads){
super(nThreads,nThreads,0L,TimeUnit.ms,new LinkedBlockingQueue());
currentThreadCount=nThreads;
executeLatch=新的原子引用(新的倒计时锁存器(0));
}
@凌驾
执行前公共无效(线程t,可运行r)
{
超级执行前(t,r);
试一试{
executelach.get().await();
}捕获(最终中断异常e){
t、 中断();
}
}
公共空间大小调整(整型){
如果(currentThreadCount==nThreads){
返回;
}
试一试{
executeLatch.getAndSet(新的倒计时锁存器(1));
currentThreadCount=nThreads;
setCorePoolSize(n个线程);
setMaximumPoolSize(n个线程);
预启动CoreThreads();
executelach.get().countDown();
}
捕获(例外e){
log.warn(“resizer捕获异常”);
}
}
}
消费者类别:
public class Consumer {
int numberOfProcessingThreads;
public Consumer(int nThreads) {
numberOfProcessingThreads = n Threads;
DynamicThreadPool threadPool = new DynamicThreadPool(nThreads);
}
public void start() {
for (int i = 0; i < messageProcessingThreads; i++)
{
threadPool.submit(new MessageConsumer.ProcessRequest());
}
}
public void updateNumberOfThreads(int newThreadCount) {
threadPool.resize(newThreadCount);
}
class ProcessRequest implements Runnable {
// 1. Logic to submit a new ProcessRequestTask if consumer is consuming messages
threadPool.submit(new MessageConsumer.ProcessRequest());
// 2. Logic to process request
}
}
公共类消费者{
int numberOfProcessingThreads;
公共消费者(int){
numberOfProcessingThreads=n个线程;
DynamicThreadPool threadPool=新的DynamicThreadPool(nThreads);
}
公开作废开始(){
for(int i=0;i
总之,当调用resize函数时,CountDownLatch设置为1,以便在executeLatch.get().await()上阻止所有线程。然后更改池大小,启动所有核心线程,并使用倒计时功能取消阻止等待的线程。
假设每次需要更新线程号时都调用updateNumberOfThreads,这种方法有意义吗
我担心的是,如果某些线程在executelach.get().await()上没有被阻塞,因为它们正在执行,那么这些线程将永远不会空闲,也永远不会停止运行。(例如,如果我们将池大小从20减少到10,但在beforeExecute方法中只有5个线程被阻塞,那么剩余的15个线程将永远不会空闲,并将继续运行)
有没有更好的方法来实现这一点?如果我没有在执行前向线程提交新任务,我如何确保线程没有处于空闲状态并且总是在处理请求?非常感谢您的帮助。
为客户端分配的固定线程数
在我看来,问题从这里开始。我说的对吗?每个客户端都有一个线程池?所谓固定线程数,是指每个客户端都有一个线程池,线程数固定。我们确保所有线程都在运行,并且在每个线程开始当前执行之前,将下一个任务提交给每个线程。