我正在寻找一种方法来限制线程数量,这些线程可以使用信号量或类似的方式运行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.acquireUninterruptibly(); // This will hang until there is a vacancy
do_my_critical_stuff();
} finally {
mySemaphore.release();
}
...就这么简单。
虽然,
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
});