我是Java核心编程的新手,目前正在从事与多线程相关的项目。
我们有多个客户调用的异步服务。我们为每个客户端有一个单独的使用者,它使用为客户端分配的固定数量的线程来消费和处理队列中的请求。现在的问题是,有些客户在一周内发送大量流量,而有些则在周末发送。 例如客户1在工作日每秒发送900个请求,而在周末仅发送200个请求。另一方面,客户2将在工作日发送100次,但在周末发送1000次。
因此,我们需要实时更新每个客户端的线程分配,而无需重新启动服务。根据我的理解,setCorePoolSize自动覆盖池大小并停止空闲线程。但是在我们的设置中,我们确保在开始执行当前任务之前始终将下一个任务提交给线程。因此线程永远不会变得空闲,并且减小池大小可能是个问题。
我看到了几篇关于执行之前或之后中断线程的文章,我尝试使用CountDownLatch编写代码段:
DynamicThreadPool类:
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");
}
}
}
消费类:
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
}
}
总而言之,当调用resize函数时,CountDownLatch设置为1,以便所有线程都在executeLatch.get()。await()上被阻塞。然后更改池大小,启动所有核心线程,并使用countDown函数取消阻止等待的线程。 假设每当需要更新线程号时都会调用updateNumberOfThreads,这种方法有意义吗?
我担心的是,如果某些线程没有因为正在执行而在executeLatch.get()。await()上被阻塞,则这些线程将永远不会变得空闲并且永远不会停止运行。 (例如,如果我们将池大小从20减少到10,但是beforeExecute方法中只有5个线程被阻塞,那么剩下的15个线程将永远不会变为空闲状态并继续运行)
是否有更好的方法来实现这一目标?如果我没有在执行之前向线程提交新任务,如何确保线程不处于空闲状态并且始终在处理请求?任何帮助表示赞赏。