我正在尋找一種方法來限制可以在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? –