我有长时间运行的代码,受到请求的影响,导致更高的资源使用率和不必要的并发问题。我的解决方案是像一个等待区域,每个线程等待一些预定义的时间。如果线程在等待时没有新请求,则继续执行该操作。任何新请求都会重新设置时钟,我们会释放前一个帖子。
之前我使用过信号量和倒计时锁存器,但它们都不适用于这种特定情况。在我编写代码之前,我想看看是否有一种标准的方法。
答案 0 :(得分:5)
我有长时间运行的代码,受到请求的影响,导致更高的资源使用率和不必要的并发问题。
听起来你应该使用受限制的ExecutorService
。您应该有一个固定数量的线程,并且不每当有新请求进入时都会创建新线程。然后,您可以通过调整池中的线程数来最大化吞吐量。
// only allow 10 concurrent requests
ExecutorService threadPool = Executors.newFixedThreadPool(10);
...
while (requestsComeIn) {
threadPool.submit(yourRunnableRequest);
}
// you need to shut the pool down once no more requests come in
threadPool.shutdown();
要限制请求,您应该使用RejectedExecutionHandler
。类似下面的代码应该在队列中有100个元素后才能使用哪些块:
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(100);
ThreadPoolExecutor threadPool =
new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, queue);
// we need our RejectedExecutionHandler to block if the queue is full
threadPool.setRejectedExecutionHandler(new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
// this will block the producer until there's room in the queue
executor.getQueue().put(r);
} catch (InterruptedException e) {
throw new RejectedExecutionException(
"Unexpected InterruptedException", e);
}
}
});
我的解决方案是拥有一个等待区域,每个线程等待一段预定义的时间。
您可以使用ThreadPoolExecutor
免费获得此信息。例如,您可以分配1个核心线程和10个最大线程,然后指定(例如)5L, TimeUnit.MINUTES
,因此如果5个额外线程中的一个休眠5分钟,它将被关闭。值得注意的是,遗憾的是,除非队列已满,否则ThreadPoolExecutor
将不会比核心线程启动更多。因此,只有在队列中有100个内容之后才会分配第二个线程。出于这个原因,我通常使核心和最大线程参数值相同。
答案 1 :(得分:2)
保持控制的最简单方法是使用队列。现代BlockingQueue
课程表现出色。然后,您可以通过改变队列的长度进行限制。
不是自己实际完成工作,而是将Job
发布到队列中,让一个或多个线程位于队列的另一端,完成所有工作。
实际上有一个现成的结构用于实现这个精确的架构,它被称为ExecutorService
。在其他地方有许多使用的例子。
有关详细信息,请参阅ExecutorService。