[英]How to manage M threads (1 per task) ensuring only N threads at the same time. With N < M. In Java
我在java中有一個任務隊列。 此隊列位於數據庫的表中。
我需要:
我想我可以這樣做:
final Semaphore semaphore = new Semaphore(N);
while (isOnJob) {
List<JobTask> tasks = getJobTasks();
if (!tasks.isEmpty()) {
final CountDownLatch cdl = new CountDownLatch(tasks.size());
for (final JobTask task : tasks) {
Thread tr = new Thread(new Runnable() {
@Override
public void run() {
semaphore.acquire();
task.doWork();
semaphore.release();
cdl.countDown();
}
});
}
cdl.await();
}
}
我知道ExecutorService類存在,但我不確定它是否可以使用它。
那么,你認為這是最好的方法嗎? 或者你能澄清一下ExecutorService如何解決這個問題嗎?
最終解決方案
我認為最好的解決方案是這樣的:
while (isOnJob) {
ExecutorService executor = Executors.newFixedThreadPool(N);
List<JobTask> tasks = getJobTasks();
if (!tasks.isEmpty()) {
for (final JobTask task : tasks) {
executor.submit(new Runnable() {
@Override
public void run() {
task.doWork();
}
});
}
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS);
}
非常感謝發型師。 BTW我正在使用連接池,但對DB的查詢非常繁重,我不希望同時擁有不受控制的任務數。
您確實可以使用ExecutorService
。 例如,使用newFixedThreadPool
方法創建一個新的固定線程池。 這樣,除了緩存線程之外,還可以保證同時運行的線程不超過n
。
這些方面的東西:
private static final ExecutorService executor = Executors.newFixedThreadPool(N);
// ...
while (isOnJob) {
List<JobTask> tasks = getJobTasks();
if (!tasks.isEmpty()) {
List<Future<?>> futures = new ArrayList<Future<?>>();
for (final JobTask task : tasks) {
Future<?> future = executor.submit(new Runnable() {
@Override
public void run() {
task.doWork();
}
});
futures.add(future);
}
// you no longer need to use await
for (Future<?> fut : futures) {
fut.get();
}
}
}
請注意,您不再需要使用鎖存器,因為如果需要, get
將等待計算完成。
我同意JG的說法, ExecutorService
是要走的路......但我認為你們都讓它變得比它需要的更復雜。
而不是創建大量的線程 (每個任務1個)為什么不只是創建一個固定大小的線程池(使用Executors.newFixedThreadPool(N)
)並將所有任務提交給它? 不需要信號量或類似的東西 - 只需在獲取它們時將作業提交到線程池,並且線程池將一次處理最多 N個線程。
如果您一次不打算使用超過N個線程,為什么要創建它們?
使用帶有未綁定隊列和固定最大線程大小的ThreadPoolExecutor實例,例如Executors.newFixedThreadPool(N) 。 這將接受大量任務,但只會同時執行N個任務。
如果您選擇一個有界隊列(容量為N ), Executor將拒絕執行任務(完全取決於您在直接使用ThreadPoolExecutor時可以配置的策略,而不是使用Executors工廠 - 請參閱RejectedExecutionHandler )。
如果您需要“真正的”擁塞控制,則應設置容量為N的綁定BlockingQueue 。 從數據庫中獲取您想要完成的任務並將它們放入隊列中 - 如果它已滿,則調用線程將阻塞。 在另一個線程(也許也開始使用Executor API)中,您從BlockingQueue 獲取任務並將它們提交給Executor 。 如果BlockingQueue為空,則調用線程也將阻塞。 表示您已完成使用“特殊”對象(例如標記隊列中最后/最后項目的單例)。
實現良好的性能還取決於線程中需要完成的工作類型。 如果您的數據庫是處理的瓶頸,我會開始關注您的線程如何訪問數據庫。 使用連接池可能是有序的。 這可能有助於您獲得更多吞吐量,因為工作線程可以重用池中的數據庫連接。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.