簡體   English   中英

如何管理M個線程(每個任務1個),同時確保只有N個線程。 N <M。在Java中

[英]How to manage M threads (1 per task) ensuring only N threads at the same time. With N < M. In Java

我在java中有一個任務隊列。 此隊列位於數據庫的表中。

我需要:

  • 每個任務僅1個線程
  • 不超過N個線程同時運行。 這是因為線程具有數據庫交互,我不希望打開一堆數據庫連接。

我想我可以這樣做:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM