我正在寻找一种方法来限制可以在Java中使用信号量或类似方法运行某段代码的线程数量。限制在Java中运行某段代码的线程数的最佳方式?
我们正在研究类似于Google Guava RateLimiter的东西 - 但不是限制每秒钟的调用次数,而是限制运行关键代码段的线程数。
之所以需要这个,是因为我们使用的某些库在这里有问题,所以我们只是寻找一个快速的解决方法。
我正在寻找一种方法来限制可以在Java中使用信号量或类似方法运行某段代码的线程数量。限制在Java中运行某段代码的线程数的最佳方式?
我们正在研究类似于Google Guava RateLimiter的东西 - 但不是限制每秒钟的调用次数,而是限制运行关键代码段的线程数。
之所以需要这个,是因为我们使用的某些库在这里有问题,所以我们只是寻找一个快速的解决方法。
这正是java.util.concurrent.Semaphore
设计做。您创建一个Semaphore
像这样:
final int MAX_NOF_THREADS = 5;
final Semaphore mySemaphore = new Semaphore(MAX_NOF_THREADS);
那么对于关键领域,你会怎么做:
try {
mySemaphore.aquire(); // This will hang until there is a vacancy
do_my_critical_stuff();
} finally {
mySemaphore.release();
}
...就这么简单。
我完全同意'Semaphore's,他们应该是这项任务的首选。不过,有一点值得一提:从技术上讲,允许一个线程进行多次获取。这意味着一些逻辑错误(例如错误的递归)可能导致线程利用率不足甚至导致死锁。但如果使用得当,它们就是这里的正确工具。 –
虽然,Semaphore
是最好的选择(请看@Bex的答案)如果你小心,也可以使用ExecutorService
。只是包装的一段代码,你想从无限的并发访问,以保护为Callable
任务,并提交这样的任务执行人服务:
// Task that will be executed
public class MyTask implements Callable<Void> {
@Override
public Void call() {
// Do the work here
return null;
}
}
// Service to execute tasks in no more than 5 parallel threads
// Cache it after creation and use when you need to execute a task
int maxThreadsCount = 5;
ExecutorService executor = Executors.newFixedThreadPool(maxThreadsCount);
// Execute a task. It will wait if all 5 threads are busy right now.
executor.submit(new MyTask());
随着ExecutorService
你也可以使用Runnable
代替Callable
,invokeAll()
代替execute
,等待任务完成,取消任务,返回值并做一些其他有用的事情。
的Java 8使它更简单,你可以使用lambda表达式而不是定义任务类:
executor.submit(() -> {
// Do the work here
});
需要记住的一点是,Executor工厂将构建由无界作业队列支持的ExecutorService实现。根据频率和运行作业的时间长短,这可能会对系统产生负面影响。在某些情况下,由于在内存中排队的作业数量有限,它可能会降低应用程序的性能。在这些情况下,可能值得创建自己的** ThreadPoolExecutor **,其中包含一个有界的工作队列和一个自定义的** RejectedExecutionHandler **。看到这段代码如何是关键的,你可能需要无限制的版本。请注意影响。 – Jeremiah
为什么不能使用java.util.concurrent.Semaphore? –