Làm thế nào để đợi tất cả các luồng kết thúc, sử dụng ExecutorService?


381

Tôi cần phải thực hiện một số lượng nhiệm vụ 4 tại một thời điểm, đại loại như thế này:

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
    taskExecutor.execute(new MyTask());
}
//...wait for completion somehow

Làm thế nào tôi có thể nhận được thông báo khi tất cả chúng đã hoàn thành? Hiện tại tôi không thể nghĩ về bất cứ điều gì tốt hơn là thiết lập một số bộ đếm nhiệm vụ toàn cầu và giảm nó vào cuối mỗi nhiệm vụ, sau đó theo dõi trong vòng lặp vô hạn bộ đếm này trở thành 0; hoặc nhận danh sách Tương lai và trong trình giám sát vòng lặp vô hạn isDone cho tất cả chúng. Các giải pháp tốt hơn không liên quan đến các vòng lặp vô hạn là gì?

Cảm ơn.

Câu trả lời:


446

Về cơ bản trên một ExecutorServicecuộc gọi bạn shutdown()và sau đó awaitTermination():

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}
taskExecutor.shutdown();
try {
  taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

9
đây chính xác là ý nghĩa của việc tắt máy / awaitTermination dành cho
matt b

31
Đó là một mô hình tốt nếu xử lý tác vụ này là một sự kiện một lần. Tuy nhiên, nếu điều này được thực hiện lặp đi lặp lại trong cùng một thời gian chạy, thì nó không tối ưu, vì bạn sẽ tạo và xé các luồng liên tục mỗi khi nó được thực thi.
sjlee

44
Tôi đang tìm kiếm bất kỳ tài liệu chính thức nào Long.MAX_VALUE, TimeUnit.NANOSECONDStương đương với việc không có thời gian chờ.
Sam Harwell

15
Tôi không thể tin rằng bạn phải sử dụng tắt máy để tham gia vào tất cả các luồng hiện tại (sau khi sử dụng tắt máy, bạn không thể sử dụng lại trình thực thi nữa). Đề xuất sử dụng danh sách Tương lai thay thế ...
rogerdpack

20
@SamHarwell xem tài liệujava.util.concurrent gói trong phần: Để đợi "mãi mãi", bạn có thể sử dụng giá trị củaTimingLong.MAX_VALUE
beluchin

174

Sử dụng CountDownLatch :

CountDownLatch latch = new CountDownLatch(totalNumberOfTasks);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
  taskExecutor.execute(new MyTask());
}

try {
  latch.await();
} catch (InterruptedException E) {
   // handle
}

và trong nhiệm vụ của bạn (kèm theo trong thử / cuối cùng)

latch.countDown();

3
Không có 4 nhiệm vụ. Có "một số nhiệm vụ" được thực hiện 4 lần.
cletus

2
Xin lỗi, tôi đã hiểu nhầm câu hỏi. Có, số lượng tác vụ sẽ là đối số cho hàm tạo CountDownLatch
ChssPly76

3
Tôi thấy giải pháp này thanh lịch hơn các giải pháp khác, có vẻ như nó được tạo ra cho mục đích này, và nó đơn giản và dễ hiểu.
wvdschel

3
Nếu bạn không biết số lượng nhiệm vụ trước khi bắt đầu thì sao?
cletus

11
@cletus - sau đó bạn không sử dụng CountDownLatch :-) Hãy nhớ rằng, tôi không tranh luận rằng phương pháp này tốt hơn phương pháp của bạn. Tuy nhiên, tôi thấy rằng trong các tình huống thực tế đời sống tôi làm biết số nhiệm vụ, cài đặt bơi thread làm cần phải được cấu hình cho mỗi triển khai, và hồ bơi có thể được tái sử dụng. Vì vậy, tôi thường có hồ bơi chủ đề tiêm bằng mùa xuân và thiết lập chúng như nguyên mẫu và tự đóng chúng xuống chỉ để chờ đợi cho đến khi kết thúc chủ đề dường như ít hơn lý tưởng.
ChssPly76

82

ExecutorService.invokeAll() nó làm cho bạn

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
List<Callable<?>> tasks; // your tasks
// invokeAll() returns when all tasks are complete
List<Future<?>> futures = taskExecutor.invokeAll(tasks);

Khó khăn sẽ đến nếu / khi bạn bắt đầu các chủ đề "4" một lần, khôn ngoan, sau đó tham gia / để hoàn thành tất cả 4 ...
rogerdpack

@rogerdpack: Tôi vẫn đang học những người thi hành và những thứ này. Nhưng đáp lại những gì bạn yêu cầu. 4 chủ đề tại một thời điểm không phải là một phần của một nhiệm vụ hàng loạt được thực hiện bằng cách sử dụng câu trả lời ở trên?
Mukul Goel

3
Phương pháp này sẽ chỉ hoạt động nếu bạn biết số lượng nhiệm vụ trước khi thực hiện.
Konstantin

3
Tôi nghĩ rằng khi futuresđược trả lại, các nhiệm vụ chưa được hoàn thành. Họ có thể hoàn thành trong tương lai và bạn sẽ có một liên kết đến kết quả. Đó là lý do tại sao nó được gọi là a Future. Bạn có phương thức Future.get () , sẽ chờ tác vụ kết thúc để có kết quả.
AlikElzin-kilaka

5
@ AlikElzin-kilaka Trích dẫn từ JavaDocs (được liên kết trong câu trả lời): "Thực thi các nhiệm vụ đã cho, trả về danh sách Tương lai giữ trạng thái và kết quả của chúng khi tất cả hoàn thành. Future.isDone () đúng với từng yếu tố của danh sách được trả về. "
Hulk

47

Bạn cũng có thể sử dụng Danh sách Tương lai:

List<Future> futures = new ArrayList<Future>();
// now add to it:
futures.add(executorInstance.submit(new Callable<Void>() {
  public Void call() throws IOException {
     // do something
    return null;
  }
}));

sau đó khi bạn muốn tham gia vào tất cả chúng, về cơ bản nó tương đương với việc tham gia trên mỗi cái, (với lợi ích bổ sung mà nó làm tăng các ngoại lệ từ các chủ đề con thành chính):

for(Future f: this.futures) { f.get(); }

Về cơ bản, mẹo là gọi .get () trên mỗi Tương lai tại một thời điểm, thay vì gọi vòng lặp vô hạn isDone () trên (tất cả hoặc mỗi). Vì vậy, bạn được đảm bảo "di chuyển" qua và vượt qua khối này ngay khi chuỗi cuối cùng kết thúc. Thông báo trước là vì lệnh .get () làm tăng các ngoại lệ, nếu một trong các luồng bị chết, bạn sẽ tăng từ điều này có thể trước khi các luồng khác kết thúc để hoàn thành [để tránh điều này, bạn có thể thêmcatch ExecutionException xung quanh cuộc gọi nhận ]. Một lưu ý khác là nó giữ một tham chiếu đến tất cả các luồng vì vậy nếu chúng có các biến cục bộ của luồng, chúng sẽ không được thu thập cho đến khi bạn vượt qua khối này (mặc dù bạn có thể khắc phục điều này, nếu nó trở thành vấn đề, bằng cách xóa Tương lai tắt ArrayList). Nếu bạn muốn biết Tương lai nào "kết thúc trước"https://stackoverflow.com/a/31885029/32453


3
Để biết "kết thúc trước", hãy sử dụng ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
ToolmakerSteve

34

Trong Java8, bạn có thể làm điều đó với CompleteableFuture :

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

3
Đây là một giải pháp rất thanh lịch.
mattvonb

ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
dùng2862544

@AdamSkywalker là awaitTermination () cần thiết sau es.shutdown ()?
gaurav

@gaurav khi bạn gọi tắt máy, một số tác vụ có thể chưa hoàn thành. Vì vậy, awaitTermination sẽ chặn chuỗi cuộc gọi cho đến khi mọi thứ được thực hiện. Nó phụ thuộc vào việc bạn có cần chờ kết quả trong chuỗi này hay không.
AdamSkywalker

@AdamSkywalker câu trả lời tuyệt vời. có ý nghĩa để không gọi awaitTermination () nếu tôi không cần đợi kết quả.
gaurav

26

Chỉ hai xu của tôi. Để vượt qua yêu cầu CountDownLatchphải biết số lượng nhiệm vụ trước đó, bạn có thể thực hiện theo cách cũ bằng cách sử dụng đơn giản Semaphore.

ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
int numberOfTasks=0;
Semaphore s=new Semaphore(0);
while(...) {
    taskExecutor.execute(new MyTask());
    numberOfTasks++;
}

try {
    s.aquire(numberOfTasks);
...

Trong nhiệm vụ của bạn chỉ cần gọi s.release()như bạn muốnlatch.countDown();


Khi thấy điều này, trước tiên tôi tự hỏi liệu nó có phải là vấn đề nếu một số releasecuộc gọi xảy ra trước acquirecuộc gọi, nhưng sau khi đọc tài liệu Semaphore, tôi thấy điều đó là ổn.
ToolmakerSteve

13

Một chút muộn để trò chơi nhưng để hoàn thành ...

Thay vì 'chờ đợi' để tất cả các nhiệm vụ hoàn thành, bạn có thể nghĩ theo nguyên tắc Hollywood, "đừng gọi cho tôi, tôi sẽ gọi cho bạn" - khi tôi kết thúc. Tôi nghĩ rằng mã kết quả là thanh lịch hơn ...

Quả ổi cung cấp một số công cụ thú vị để thực hiện điều này.

Một ví dụ ::

Kết hợp một ExecutorService vào ListeningExecutorService ::

ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));

Gửi một bộ sưu tập các cuộc gọi để thực hiện ::

for (Callable<Integer> callable : callables) {
  ListenableFuture<Integer> lf = service.submit(callable);
  // listenableFutures is a collection
  listenableFutures.add(lf)
});

Bây giờ là phần thiết yếu:

ListenableFuture<List<Integer>> lf = Futures.successfulAsList(listenableFutures);

Đính kèm một cuộc gọi lại vào ListenableFuture, mà bạn có thể sử dụng để được thông báo khi tất cả các hợp đồng tương lai hoàn thành ::

        Futures.addCallback(lf, new FutureCallback<List<Integer>>() {
        @Override
        public void onSuccess(List<Integer> result) {
            log.info("@@ finished processing {} elements", Iterables.size(result));
            // do something with all the results
        }

        @Override
        public void onFailure(Throwable t) {
            log.info("@@ failed because of :: {}", t);
        }
    });

Điều này cũng mang lại lợi thế là bạn có thể thu thập tất cả các kết quả ở một nơi sau khi quá trình xử lý kết thúc ...

Thêm thông tin ở đây


2
Rất sạch sẽ. Không hoạt động hoàn hảo ngay cả trên Android. Chỉ cần sử dụng runOnUiThread()trong onSuccess().
DSchmidt

12

Lớp CyclicBarrier trong Java 5 trở lên được thiết kế cho loại điều này.


7
Thật tuyệt, không bao giờ có thể nhớ tên của cấu trúc dữ liệu này. Tuy nhiên, chỉ phù hợp nếu bạn biết trước số lượng nhiệm vụ sẽ được xếp hàng.
ᆼ ᆺ

vâng, bạn nghĩ rằng bạn có thể vượt qua rào cản với luồng hiện tại và tất cả các luồng con, sau đó khi bạn vượt qua, bạn sẽ biết các luồng con đã được thực hiện ...
rogerdpack

Thật ra đó là câu trả lời sai. CyclicBarrier được thiết kế cho các phần. CountDownLatch được thiết kế cho sự kiện chờ đợi
gstackoverflow 16/2/2017

7

Thực hiện theo một trong các cách tiếp cận dưới đây.

  1. Duyệt qua tất cả tương lai nhiệm vụ, trở về từ submittrên ExecutorServicevà kiểm tra tình trạng với chặn cuộc gọi get()trên Futuređối tượng theo đề nghị củaKiran
  2. Sử dụng invokeAll()trên ExecutorService
  3. CountDownLatch
  4. ForkJoinPool hoặc Executors.html # newWorkStealsPool
  5. Sử dụng shutdown, awaitTermination, shutdownNowAPI của ThreadPoolExecutor theo trình tự thích hợp

Câu hỏi SE liên quan:

CountDownLatch được sử dụng như thế nào trong đa luồng Java?

Làm thế nào để tắt java ExecutorService đúng cách


6

Đây là hai lựa chọn, chỉ cần nhầm lẫn cái nào là tốt nhất để đi.

Lựa chọn 1:

ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
                               .map(task -> CompletableFuture.runAsync(task, es))
                               .toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();    
es.shutdown();

Lựa chọn 2:

ExecutorService es = Executors.newFixedThreadPool(4);
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
    futures.add(es.submit(task));
}

for(Future<?> future : futures) {
    try {
        future.get();
    }catch(Exception e){
        // do logging and nothing else
    }
}
es.shutdown();

Ở đây đặt tương lai.get (); Trong thử bắt là ý tưởng tốt phải không?


5

Bạn có thể gói các nhiệm vụ của mình trong một runnable khác, nó sẽ gửi thông báo:

taskExecutor.execute(new Runnable() {
  public void run() {
    taskStartedNotification();
    new MyTask().run();
    taskFinishedNotification();
  }
});

1
Mất một lúc tôi mới thấy điều này sẽ giải quyết câu hỏi của OP như thế nào. Đầu tiên, lưu ý rằng gói này là của từng tác vụ, không phải của mã bắt đầu tất cả các tác vụ. Có lẽ, mỗi lần bắt đầu sẽ tăng một bộ đếm và mỗi lần kết thúc sẽ làm giảm bộ đếm đó hoặc sẽ tăng một bộ completedđếm. Vì vậy, sau khi bắt đầu tất cả, tại mỗi thông báo, có thể xác định liệu tất cả các nhiệm vụ đã hoàn thành hay chưa. Lưu ý rằng điều quan trọng là sử dụng try/finallyđể thông báo kết thúc (hoặc thông báo thay thế trong catchkhối) được đưa ra ngay cả khi tác vụ thất bại. Nếu không, sẽ chờ mãi.
ToolmakerSteve

3

Tôi vừa mới viết một chương trình mẫu giải quyết vấn đề của bạn. Không có triển khai ngắn gọn được đưa ra, vì vậy tôi sẽ thêm một. Mặc dù bạn có thể sử dụng executor.shutdown()executor.awaitTermination(), đó không phải là cách thực hành tốt nhất vì thời gian của các luồng khác nhau sẽ không thể đoán trước được.

ExecutorService es = Executors.newCachedThreadPool();
    List<Callable<Integer>> tasks = new ArrayList<>();

    for (int j = 1; j <= 10; j++) {
        tasks.add(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                int sum = 0;
                System.out.println("Starting Thread "
                        + Thread.currentThread().getId());

                for (int i = 0; i < 1000000; i++) {
                    sum += i;
                }

                System.out.println("Stopping Thread "
                        + Thread.currentThread().getId());
                return sum;
            }

        });
    }

    try {
        List<Future<Integer>> futures = es.invokeAll(tasks);
        int flag = 0;

        for (Future<Integer> f : futures) {
            Integer res = f.get();
            System.out.println("Sum: " + res);
            if (!f.isDone()) 
                flag = 1;
        }

        if (flag == 0)
            System.out.println("SUCCESS");
        else
            System.out.println("FAILED");

    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }

Thật tốt khi bạn hiển thị việc sử dụng tương lai.get - lựa chọn tốt để biết về. Nhưng tại sao bạn nghĩ rằng tốt hơn là chờ đợi mãi mãi , hơn là đặt một số thời gian chờ tối đa chấp nhận được? Quan trọng hơn, không có lý do gì để thực hiện tất cả logic này, khi người ta có thể chỉ cần đưa ra một thời gian thực sự rất dài để chờ đợi, nếu bạn muốn chờ đợi (về cơ bản là mãi mãi) cho đến khi tất cả các nhiệm vụ hoàn thành.
ToolmakerSteve

Điều này không khác với các giải pháp đã được trình bày ở đây. Giải pháp chính xác của bạn giống như được trình bày bởi @sjlee
bột giấy_fiction

Không chắc chắn lý do tại sao bạn cần kiểm tra xong khi theo tài liệu oracle, invoke ALL sẽ chỉ trở lại "khi tất cả hết hạn hoặc hết thời gian, bất cứ điều gì xảy ra trước"
Mashrur

3

Chỉ cần cung cấp nhiều lựa chọn thay thế ở đây khác nhau để sử dụng chốt / rào cản. Bạn cũng có thể nhận được kết quả một phần cho đến khi tất cả chúng kết thúc bằng cách sử dụng CompleteionService .

Từ thực tế đồng thời Java: "Nếu bạn có một loạt các tính toán để gửi cho Executor và bạn muốn lấy kết quả của chúng khi chúng có sẵn, bạn có thể giữ lại Tương lai liên quan đến từng nhiệm vụ và liên tục thăm dò ý kiến ​​để hoàn thành bằng cách gọi get với thời gian chờ bằng không. Điều này là có thể, nhưng tẻ nhạt . May mắn thay, có một cách tốt hơn : một dịch vụ hoàn thành. "

Đây là việc thực hiện

public class TaskSubmiter {
    private final ExecutorService executor;
    TaskSubmiter(ExecutorService executor) { this.executor = executor; }
    void doSomethingLarge(AnySourceClass source) {
        final List<InterestedResult> info = doPartialAsyncProcess(source);
        CompletionService<PartialResult> completionService = new ExecutorCompletionService<PartialResult>(executor);
        for (final InterestedResult interestedResultItem : info)
            completionService.submit(new Callable<PartialResult>() {
                public PartialResult call() {
                    return InterestedResult.doAnOperationToGetPartialResult();
                }
        });

    try {
        for (int t = 0, n = info.size(); t < n; t++) {
            Future<PartialResult> f = completionService.take();
            PartialResult PartialResult = f.get();
            processThisSegment(PartialResult);
            }
        } 
        catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } 
        catch (ExecutionException e) {
            throw somethinghrowable(e.getCause());
        }
    }
}

3

Đây là giải pháp của tôi, dựa trên mẹo "AdamSkywalker", và nó hoạt động

package frss.main;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestHilos {

    void procesar() {
        ExecutorService es = Executors.newFixedThreadPool(4);
        List<Runnable> tasks = getTasks();
        CompletableFuture<?>[] futures = tasks.stream().map(task -> CompletableFuture.runAsync(task, es)).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(futures).join();
        es.shutdown();

        System.out.println("FIN DEL PROCESO DE HILOS");
    }

    private List<Runnable> getTasks() {
        List<Runnable> tasks = new ArrayList<Runnable>();

        Hilo01 task1 = new Hilo01();
        tasks.add(task1);

        Hilo02 task2 = new Hilo02();
        tasks.add(task2);
        return tasks;
    }

    private class Hilo01 extends Thread {

        @Override
        public void run() {
            System.out.println("HILO 1");
        }

    }

    private class Hilo02 extends Thread {

        @Override
        public void run() {
            try {
                sleep(2000);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("HILO 2");
        }

    }


    public static void main(String[] args) {
        TestHilos test = new TestHilos();
        test.procesar();
    }
}

2

Bạn có thể sử dụng mã này:

public class MyTask implements Runnable {

    private CountDownLatch countDownLatch;

    public MyTask(CountDownLatch countDownLatch {
         this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
         try {
             //Do somethings
             //
             this.countDownLatch.countDown();//important
         } catch (InterruptedException ex) {
              Thread.currentThread().interrupt();
         }
     }
}

CountDownLatch countDownLatch = new CountDownLatch(NUMBER_OF_TASKS);
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
for (int i = 0; i < NUMBER_OF_TASKS; i++){
     taskExecutor.execute(new MyTask(countDownLatch));
}
countDownLatch.await();
System.out.println("Finish tasks");

2

Tôi đã tạo ra ví dụ làm việc sau đây. Ý tưởng là có một cách để xử lý một nhóm các nhiệm vụ (tôi đang sử dụng một hàng đợi làm ví dụ) với nhiều Chủ đề (được xác định theo chương trình theo sốOfT Nhiệm vụ / ngưỡng) và đợi cho đến khi tất cả các Chủ đề được hoàn thành để tiếp tục xử lý.

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** Testing CountDownLatch and ExecutorService to manage scenario where
 * multiple Threads work together to complete tasks from a single
 * resource provider, so the processing can be faster. */
public class ThreadCountDown {

private CountDownLatch threadsCountdown = null;
private static Queue<Integer> tasks = new PriorityQueue<>();

public static void main(String[] args) {
    // Create a queue with "Tasks"
    int numberOfTasks = 2000;
    while(numberOfTasks-- > 0) {
        tasks.add(numberOfTasks);
    }

    // Initiate Processing of Tasks
    ThreadCountDown main = new ThreadCountDown();
    main.process(tasks);
}

/* Receiving the Tasks to process, and creating multiple Threads
* to process in parallel. */
private void process(Queue<Integer> tasks) {
    int numberOfThreads = getNumberOfThreadsRequired(tasks.size());
    threadsCountdown = new CountDownLatch(numberOfThreads);
    ExecutorService threadExecutor = Executors.newFixedThreadPool(numberOfThreads);

    //Initialize each Thread
    while(numberOfThreads-- > 0) {
        System.out.println("Initializing Thread: "+numberOfThreads);
        threadExecutor.execute(new MyThread("Thread "+numberOfThreads));
    }

    try {
        //Shutdown the Executor, so it cannot receive more Threads.
        threadExecutor.shutdown();
        threadsCountdown.await();
        System.out.println("ALL THREADS COMPLETED!");
        //continue With Some Other Process Here
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }
}

/* Determine the number of Threads to create */
private int getNumberOfThreadsRequired(int size) {
    int threshold = 100;
    int threads = size / threshold;
    if( size > (threads*threshold) ){
        threads++;
    }
    return threads;
}

/* Task Provider. All Threads will get their task from here */
private synchronized static Integer getTask(){
    return tasks.poll();
}

/* The Threads will get Tasks and process them, while still available.
* When no more tasks available, the thread will complete and reduce the threadsCountdown */
private class MyThread implements Runnable {

    private String threadName;

    protected MyThread(String threadName) {
        super();
        this.threadName = threadName;
    }

    @Override
    public void run() {
        Integer task;
        try{
            //Check in the Task pool if anything pending to process
            while( (task = getTask()) != null ){
                processTask(task);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }finally {
            /*Reduce count when no more tasks to process. Eventually all
            Threads will end-up here, reducing the count to 0, allowing
            the flow to continue after threadsCountdown.await(); */
            threadsCountdown.countDown();
        }
    }

    private void processTask(Integer task){
        try{
            System.out.println(this.threadName+" is Working on Task: "+ task);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}
}

Hy vọng nó giúp!


1

Bạn có thể sử dụng lớp con ExecutorCompletionServicetaskExecutor của riêng bạn để bọc và triển khai BlockingQueue của riêng bạn để được thông báo khi mỗi tác vụ hoàn thành và thực hiện bất kỳ cuộc gọi lại hoặc hành động nào khác mà bạn mong muốn khi số lượng tác vụ hoàn thành đạt được mục tiêu mong muốn của bạn.


1

bạn nên sử dụng executorService.shutdown()executorService.awaitTerminationphương pháp.

Một ví dụ như sau:

public class ScheduledThreadPoolExample {

    public static void main(String[] args) throws InterruptedException {
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        executorService.scheduleAtFixedRate(() -> System.out.println("process task."),
                0, 1, TimeUnit.SECONDS);

        TimeUnit.SECONDS.sleep(10);
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
    }

}

là awaitTermination () cần thiết sau khi tắt máy () /
gaurav

1

Vì vậy, tôi đăng câu trả lời của mình từ câu hỏi được liên kết ở đây, trong trường hợp ai đó muốn một cách đơn giản hơn để làm điều này

ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture[] futures = new CompletableFuture[10];
int i = 0;
while (...) {
    futures[i++] =  CompletableFuture.runAsync(runner, executor);
}

CompletableFuture.allOf(futures).join(); // THis will wait until all future ready.

0

Java 8 - Chúng tôi có thể sử dụng API luồng để xử lý luồng. Vui lòng xem đoạn trích dưới đây

final List<Runnable> tasks = ...; //or any other functional interface
tasks.stream().parallel().forEach(Runnable::run) // Uses default pool

//alternatively to specify parallelism 
new ForkJoinPool(15).submit(
          () -> tasks.stream().parallel().forEach(Runnable::run) 
    ).get();

2
Xin chào Vlad, chào mừng bạn đến với StackOverflow. Bạn có thể vui lòng chỉnh sửa câu trả lời của mình để giải thích cách trả lời câu hỏi này không, và mã này làm gì? Mã chỉ có câu trả lời được khuyến khích ở đây. Cảm ơn bạn!
Tim Malone

Bài này nói về sự tương tranh. Parallelism! = Đồng thời
GabrielBB

0

ExecutorService WORKER_THREAD_POOL 
  = Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(2);
for (int i = 0; i < 2; i++) {
    WORKER_THREAD_POOL.submit(() -> {
        try {
            // doSomething();
            latch.countDown();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    });
}

// wait for the latch to be decremented by the two remaining threads
latch.await();

Nếu doSomething()ném một số ngoại lệ khác, latch.countDown()dường như sẽ không thực thi, vậy tôi nên làm gì?


0

nếu bạn sử dụng nhiều chủ đề ExecutService SEQUENTIALLY và muốn đợi MACHI EXECUTIONSERVICE kết thúc. Cách tốt nhất là như dưới đây;

ExecutorService executer1 = Executors.newFixedThreadPool(THREAD_SIZE1);
for (<loop>) {
   executer1.execute(new Runnable() {
            @Override
            public void run() {
                ...
            }
        });
} 
executer1.shutdown();

try{
   executer1.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

   ExecutorService executer2 = Executors.newFixedThreadPool(THREAD_SIZE2);
   for (true) {
      executer2.execute(new Runnable() {
            @Override
            public void run() {
                 ...
            }
        });
   } 
   executer2.shutdown();
} catch (Exception e){
 ...
}

-1

Điều này có thể giúp

Log.i(LOG_TAG, "shutting down executor...");
executor.shutdown();
while (true) {
                try {
                    Log.i(LOG_TAG, "Waiting for executor to terminate...");
                    if (executor.isTerminated())
                        break;
                    if (executor.awaitTermination(5000, TimeUnit.MILLISECONDS)) {
                        break;
                    }
                } catch (InterruptedException ignored) {}
            }

-1

Bạn có thể gọi WaitTillDone () trên lớp Runner này :

Runner runner = Runner.runner(4); // create pool with 4 threads in thread pool

while(...) {
    runner.run(new MyTask()); // here you submit your task
}


runner.waitTillDone(); // and this blocks until all tasks are finished (or failed)


runner.shutdown(); // once you done you can shutdown the runner

Bạn có thể sử dụng lại lớp này và gọi WaitTillDone () bao nhiêu lần bạn muốn trước khi gọi shutdown (), cộng với mã của bạn cực kỳ đơn giản . Ngoài ra, bạn không cần phải biết các số nhiệm vụ trả trước.

Để sử dụng nó, chỉ cần thêm gradle / maven này compile 'com.github.matejtymes:javafixes:1.3.1' phụ thuộc vào dự án của bạn.

Nhiều thông tin thêm có thế được tìm thấy ở đây:

https://github.com/MatejTymes/JavaFixes


-2

Có một phương thức trong bộ thực thi getActiveCount()- cung cấp số lượng luồng hoạt động.

Sau khi kéo dài chuỗi, chúng ta có thể kiểm tra xem activeCount()giá trị là 0. Khi giá trị bằng 0, điều đó có nghĩa là không có luồng hoạt động nào đang chạy có nghĩa là nhiệm vụ đã kết thúc:

while (true) {
    if (executor.getActiveCount() == 0) {
    //ur own piece of code
    break;
    }
}

3
Không phải là một ý tưởng hay, xem stackoverflow.com/a/7271685/1166992 và javadoc: "Trả về số lượng chủ đề gần đúng đang tích cực thực hiện các tác vụ."
Olivier Faucheux
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.