ExecutorService kullanarak tüm evrelerin bitmesini nasıl bekleyebilirim?


381

Ben böyle bir şey, bir seferde görevler 4 bir miktar yürütmek gerekiyor:

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

Hepsi tamamlandığında nasıl bildirim alabilirim? Şimdilik, bazı küresel görev sayacı ayarlamak ve her görevin sonunda azaltmak daha iyi bir şey düşünemiyorum, daha sonra bu sayaç 0 olmak için sonsuz döngüde izlemek; veya Vadeli İşlemlerin bir listesini alın ve sonsuz döngü izleyici hepsi için yapılır. Sonsuz döngüler içermeyen daha iyi çözümler nelerdir?

Teşekkürler.

Yanıtlar:


446

Temelde bir ExecutorServiceçağrı shutdown()ve sonra 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
Bu tam olarak kapatma / beklemenin ne anlama geldiğini gösterir
matt b

31
Bu görev işleme bir kerelik bir olay ise iyi bir modeldir. Bununla birlikte, aynı çalışma zamanı boyunca tekrar tekrar yapılırsa, her yürütüldüğünde tekrar tekrar iş parçacıkları oluşturacağınız ve yırttığınız için bu optimum değildir.
sjlee

44
Long.MAX_VALUE, TimeUnit.NANOSECONDSZaman aşımı olmamasına eşdeğer herhangi bir resmi belge arıyorum .
Sam Harwell

15
Tüm geçerli iş parçacıklarına katılmak için kapatma kullanmanız gerektiğine inanamıyorum (kapatmayı kullandıktan sonra tekrar yürütücüyü kullanamazsınız). Bunun yerine Geleceğin listesini kullanmanızı
öneririz

20
@SamHarwell bölümünün altındaki java.util.concurrentpaket belgelerineTiming bakın: "Sonsuza kadar" beklemek içinLong.MAX_VALUE
beluchin

174

CountDownLatch kullanın :

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

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

ve görevinizde (denemeye / son olarak ekleyin)

latch.countDown();

3
4 görev yok. Bir seferde 4 yapılan "bazı görevler" vardır.
cletus

2
Üzgünüm, soruyu yanlış anladım. Evet, görev sayısı CountDownLatch yapıcısı için argüman olmalıdır
ChssPly76

3
Bu çözümü diğerlerinden daha zarif buluyorum, bu amaç için yapılmış gibi görünüyor ve basit ve anlaşılır.
wvdschel

3
Başlamadan önce görev sayısını bilmiyorsanız ne olur?
cletus

11
@cletus - bir CountDownLatch kullanmıyorsunuz :-) Dikkat edin, bu yaklaşımın sizinkinden daha iyi olduğunu iddia etmiyorum. Ancak, gerçek hayatta senaryolarında bunu buldum do görevlerin sayısını bilmek, iplik havuzu ayarları yapmak dağıtım başına yapılandırılabilir olması gerekir ve havuzlar olabilir tekrar kullanılabilir. Bu yüzden genellikle Spring tarafından enjekte edilen iplik havuzlarım var ve bunları prototip olarak ayarlıyorum ve sadece ipliklerin bitmesini beklemek için manuel olarak kapatıyorum ideal olmaktan daha az görünüyor.
ChssPly76

82

ExecutorService.invokeAll() sizin için yapar.

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

Zorluk, "4" iş parçacıklarını teker teker başlattığınız zaman / parça halinde, daha sonra 4'e katılın / bitirin ...
rogerdpack

@rogerdpack: Hala bu uygulayıcıları ve şeyleri öğreniyorum. Ama sorduğunuza yanıt olarak. Bir kerede 4 iş parçacığı, yukarıdaki yanıt kullanılarak yürütülen bir toplu işin parçası olmamalı mı?
Mukul Goel

3
Bu yöntem yalnızca önceden görev sayısını biliyorsanız çalışır.
Konstantin

3
Ben futuresgeri döndüğünde, görevlerin tamamlanmadığını düşünüyorum. Gelecekte tamamlanabilirler ve sonuca bir bağlantınız olur. Bu yüzden a denir Future. Görevin bir sonucu almasını bekleyen Future.get () yöntemine sahipsiniz .
AlikElzin-kilaka

5
@ AlikElzin-kilaka JavaDocs'tan alıntı (cevaba bağlı olarak): "Verilen görevleri yürütür, tamamlandığında durumlarını ve sonuçlarını tutan bir Futures listesini döndürür. Future.isDone (), döndürülen listenin her öğesi için doğrudur. "
Hulk

47

Vadeli İşlem Listeleri'ni de kullanabilirsiniz:

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;
  }
}));

hepsine katılmak istediğinizde, aslında her birine katılmaya eşdeğerdir (ek avantajı, çocuk iş parçacıklarından ana listeye istisnaları yeniden arttırmasıyla birlikte):

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

Temel olarak hile isDone () çağrısı (tümü veya her biri) yerine, her bir Gelecekte .get () öğesini teker teker çağırmaktır. Böylece, son iş parçacığı biter bitmez bu blok boyunca "ilerlemeniz" garanti edilir. Uyarı, .get () çağrısının istisnaları yeniden yükseltmesi nedeniyle, iş parçacıklarından biri ölürse, diğer iş parçacıklarının tamamlanması bitmeden önce bundan yükselirsiniz [bundan kaçınmak catch ExecutionExceptioniçin get çağrısının etrafına ]. Diğer uyarı, tüm yerel iş parçacığı için bir referans tutar, böylece yerel değişkenleri iş parçacığı varsa, bu bloğu geçene kadar toplanmazlar (bir sorun haline geldiğinde, bir sorun olursa, kaldırarak Gelecek ArrayList dışında). Hangi Geleceğin "önce bittiğini" bilmek istiyorsanızhttps://stackoverflow.com/a/31885029/32453


3
Hangi "önce bittiğini" bilmek için şunu kullanın ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
ToolmakerSteve

34

Java8'de CompletableFuture ile yapabilirsiniz :

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
Bu çok zarif bir çözüm.
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 } }
user2862544

@AdamSkywalker es.shutdown () öğesinden sonra awaitTermination () gerekli midir?
gaurav

@gaurav komutunu çağırdığınızda, bazı görevler henüz tamamlanmamış olabilir. Yani awaitTermination, her şey yapılana kadar çağıran evreyi engelleyecektir. Bu konudaki sonuçları beklemeniz gerekip gerekmediğine bağlıdır.
AdamSkywalker

@AdamSkywalker harika bir cevap. sonuçları beklemem gerekmiyorsa awaitTermination () işlevini çağırmamak mantıklıdır.
gaurav

26

Sadece iki sentim. CountDownLatchÖnceden görev sayısını bilmenin gerekliliğini aşmak için , basit bir yöntemle eski moda yolunu yapabilirsiniz Semaphore.

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

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

Görevinde sadece s.release()istediğin gibi aralatch.countDown();


Bunu gördükten sonra release, acquirearamadan önce bazı çağrılar olursa bir sorun olup olmadığını merak ettim , ancak Semaphore belgelerini okuduktan sonra bunun iyi olduğunu görüyorum.
ToolmakerSteve

13

Oyuna biraz geç ama tamamlanma uğruna ...

Tüm görevlerin bitmesini 'beklemek' yerine, Hollywood prensibi, "beni arama, seni arayacağım" - bitirdiğim zaman düşünebilirsiniz. Bence ortaya çıkan kod daha zarif ...

Guava bunu başarmak için bazı ilginç araçlar sunuyor.

Bir örnek ::

Bir ExecutorService öğesini ListeningExecutorService ::

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

Yürütmek için bir callables koleksiyonu gönderin ::

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

Şimdi önemli olan:

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

Tüm futures tamamlandığında bilgilendirilmek için kullanabileceğiniz ListenableFuture'a bir geri arama ekleyin:

        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);
        }
    });

Bu, işlem bittikten sonra tüm sonuçları tek bir yerde toplayabilme avantajı sunar ...

Daha fazla bilgi burada


2
Çok temiz. Android'de bile kusursuz çalışır. Sadece kullanmak zorunda runOnUiThread()içinde onSuccess().
DSchmidt

12

CyclicBarrier sınıfı Java 5 ve sonrası bu tür bir şey için tasarlanmıştır.


7
Harika, bu veri yapısının adını asla hatırlayamıyorum. Ancak, yalnızca sıraya alınacak görevlerin miktarını önceden biliyorsanız uygun olur.
ᆼ ᆺ ᆼ

evet mevcut iş parçacığı ve tüm alt iş parçacığı ile bariyere vurabileceğini düşünürdün, o zaman geçtikten sonra çocuk iş parçacıklarının yapıldığını
bileceksin

Aslında yanlış cevap. Bölümler için tasarlanmış CyclicBarrier. CountDownLatch bekleyen olay için tasarlanmış
gstackoverflow

7

Aşağıdaki yaklaşımlardan birini izleyin.

  1. Bıkmadan bütün yoluyla Gelecek dönen görevler, submitilgili ExecutorServiceçağrıyı engelleme ile durum ve kontrol get()üzerindeFuture önerdiği gibi nesneKiran
  2. Kullanım invokeAll()üzerindeki ExecutorService
  3. CountDownLatch
  4. ForkJoinPool veya Executors.html # newWorkStealingPool
  5. shutdown, awaitTermination, shutdownNowThreadPoolExecutor API'lerini uygun sırayla kullanın

İlgili SE soruları:

CountDownLatch, Java Multithreading'de nasıl kullanılır?

Java ExecutorService nasıl düzgün kapatılır


6

İşte iki seçenek, sadece hangisinin gitmek için en iyisi olduğunu karıştırmayın.

Seçenek 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();

Seçenek 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();

Burada future.get (); denemek yakalamak iyi bir fikir değil mi?


5

Görevlerinizi bildirimler gönderecek başka bir çalıştırılabilir dosyaya sarabilirsiniz:

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

1
Bunun OP'nin sorusunu nasıl çözeceğini görmek için biraz zaman aldım. İlk olarak, bu kaydırmanın tüm görevleri başlatan koddan değil, her görevin olduğunu unutmayın . Muhtemelen, her başlangıç ​​bir sayacı arttırır ve her bitiş bu sayacı azaltır veya bir completedsayacı arttırır. Böylece, hepsini başlattıktan sonra, her bildirimde, tüm görevlerin tamamlanıp tamamlanmadığını belirleyebilir. Kullanımı hayati önem taşıdığını Not try/finallybitmiş bir bildirim (veya alternatif bir bildirim böylece catchbloğun) bir görev başarısız olsa bile verilir. Aksi takdirde sonsuza kadar beklerdim.
ToolmakerSteve

3

Sorununuzu çözen örnek bir program yazdım. Kısa bir uygulama yapılmadığı için bir tane ekleyeceğim. Kullanabileceğiniz gibi executor.shutdown()ve executor.awaitTermination(), farklı iş parçacıkları tarafından geçen süre tahmin edilemeyeceği için en iyi uygulama değildir.

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();
    }

Future.get - kullanımını bilmeniz iyi bir şey. Ama neden sonsuza kadar beklemeyi kabul edilebilir maksimum zaman aşımı ayarlamak yerine daha iyi buluyorsunuz ? Daha da önemlisi, tüm görevler tamamlanana kadar (esasen sonsuza kadar) beklemek istiyorsanız, Beklemeyi gerçekten, gerçekten çok uzun bir süre verebildiği zaman, tüm bu mantığı yapmak için hiçbir neden yoktur.
ToolmakerSteve

Bu, burada sunulan çözümlerden farklı değildir. Adil çözümünüz @sjlee
pulp_fiction

Neden oracle doc göre yapılan kontrol etmek için emin değilim, invokeAll sadece "tüm tamamlandığında veya zaman aşımı süresi dolduğunda, hangisi önce olursa"
dönecektir

3

Sadece mandal / bariyer kullanmak için farklı daha fazla alternatif sağlamak için. Ayrıca, CompletionService'i kullanarak tümü bitene kadar kısmi sonuçları da alabilirsiniz .

Uygulamadaki Java Concurrency'dan: "Bir Yöneticiye göndermek için bir grup hesaplamanız varsa ve sonuçlarını kullanılabilir hale geldiklerinde almak istiyorsanız, her bir görevle ilişkili Geleceği koruyabilir ve bir zaman aşımı. Bu mümkün, ancak sıkıcı . Neyse ki daha iyi bir yol var : bir tamamlama hizmeti. "

İşte uygulama

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

Bu benim çözümüm, "AdamSkywalker" ipucuna dayanıyor ve işe yarıyor

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

Bu kodu kullanabilirsiniz:

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

Aşağıdaki çalışma örneğini oluşturdum. Fikir, bir görev havuzunu (örnek olarak bir kuyruk kullanıyorum) birçok Konu ile (numberOfTasks / eşik ile programlı olarak belirlenir) işlemek ve diğer İşlemlere devam etmek için tüm Konuların tamamlanmasını bekleyin.

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();
        }
    }
}
}

Umarım yardımcı olur!


1

Sen kendi alt sınıfını kullanabilirsiniz ExecutorCompletionService şal taskExecutorve kendi uygulama BlockingQueue zaman her görev tamamlanana bilgi almak için ve tamamlanan görevlerin sayısı, istenen hedefe ulaştığında ne arzu geri arama veya diğer eylem gerçekleştirin.


1

executorService.shutdown()ve executorService.awaitTerminationyöntemini kullanmalısınız .

Aşağıdaki gibi bir örnek:

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);
    }

}

kapatma işleminden sonra gerekli aermiterminasyon () /
gaurav

1

Bu yüzden, bağlantılı sorudan cevabımı buraya gönderiyorum, birinin bunu yapmak için daha basit bir yol istemesi durumunda

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 - Akışı işlemek için akış API'sini kullanabiliriz. Lütfen aşağıdaki pasaja bakın

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
Merhaba Vlad, StackOverflow'a hoş geldiniz. Bunun soruyu nasıl yanıtladığını ve kodun ne yaptığını açıklamak için lütfen cevabınızı düzenleyebilir misiniz? Burada yalnızca kod yanıtları önerilmez. Teşekkür ederim!
Tim Malone

Bu yazı eşzamanlılıktan bahsediyor. Paralellik! = Eşzamanlılık
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();

doSomething()Başka istisnalar atarsa, görünüşü latch.countDown()yürütülmez, bu yüzden ne yapmalıyım?


0

Daha fazla iş parçacığı ExecutionServices SIRALI olarak kullanırsanız ve HER EXECUTIONSERVICE'ın bitmesini beklemek istiyorsanız. En iyi yol aşağıdaki gibidir;

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

Bu yardımcı olabilir

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

Bu Runner sınıfında waitTillDone () öğesini çağırabilirsiniz :

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

Bu sınıfı yeniden kullanabilir ve shutdown () öğesini çağırmadan önce waitTillDone () öğesini istediğiniz kadar çağırabilirsiniz, ayrıca kodunuz son derece basittir . Ayrıca bilmek zorunda değilsiniz görevlerin sayısını peşin.

Kullanmak için sadece bu gradle / maven'i ekleyin compile 'com.github.matejtymes:javafixes:1.3.1' için projenize bağımlılığını ekleyin.

Daha fazla ayrıntıyı burada bulabilirsiniz:

https://github.com/MatejTymes/JavaFixes


-2

Yürütücüde getActiveCount()etkin iş parçacığı sayısını veren bir yöntem vardır .

İpliği yaydıktan sonra activeCount()değerin olup olmadığını kontrol edebiliriz 0. Değer sıfır olduğunda, şu anda çalışan etkin iş parçacığı olmadığı anlamına gelir, bu da görevin tamamlandığı anlamına gelir:

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

3
İyi bir fikir değil, bkz. Stackoverflow.com/a/7271685/1166992 ve javadoc: "Görevleri etkin olarak yürüten yaklaşık iş parçacığı sayısını döndürür."
Olivier Faucheux
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.