ExecutorService का उपयोग करके सभी थ्रेड्स के खत्म होने का इंतजार कैसे करें?


381

मुझे एक बार में कुछ कार्यों की मात्रा ४ को निष्पादित करने की आवश्यकता है, कुछ इस प्रकार है:

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

सभी के पूर्ण होने के बाद मुझे कैसे सूचित किया जा सकता है? अभी के लिए मैं कुछ वैश्विक टास्क काउंटर सेट करने से बेहतर कुछ भी नहीं सोच सकता और हर कार्य के अंत में इसे कम कर सकता हूं, फिर अनंत लूप में निगरानी करें ताकि यह काउंटर 0 हो जाए; या उन सभी के लिए फ्यूचर्स और अनंत लूप मॉनिटर की सूची प्राप्त करें। अनंत छोरों को शामिल नहीं करने वाले बेहतर समाधान क्या हैं?

धन्यवाद।

जवाबों:


446

मूल रूप से ExecutorServiceआप एक कॉल पर shutdown()और फिर 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
यह ठीक वही है जो शटडाउन / प्रतीक्षारत है
मैट बी

31
यह एक अच्छा पैटर्न है अगर यह कार्य संभालना एक बार की घटना है। यदि यह एक ही रनटाइम के दौरान बार-बार किया जाता है, हालांकि, यह इष्टतम नहीं है, जैसा कि आप हर बार निष्पादित होने पर थ्रेड्स को बार-बार बनाते और फाड़ेंगे।
sjlee

44
मैं किसी भी आधिकारिक दस्तावेज की तलाश में हूं Long.MAX_VALUE, TimeUnit.NANOSECONDSजो टाइमआउट न होने के बराबर है।
सैम हैरवेल

15
मुझे विश्वास नहीं हो रहा है कि आपको सभी वर्तमान थ्रेड्स में शामिल होने के लिए शटडाउन का उपयोग करना होगा (शटडाउन का उपयोग करने के बाद, आप कभी भी निष्पादक का उपयोग नहीं कर सकते हैं)। भविष्य की जगह की सूची का उपयोग करके सुझाव दें ...
16

20
@SamHarwell अनुभाग के तहत java.util.concurrentपैकेज प्रलेखन देखें Timing: "हमेशा के लिए" प्रतीक्षा करने के लिए, आप Long.MAX_VALUE
beluchin

174

एक CountDownLatch का उपयोग करें :

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

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

और अपने कार्य के भीतर (कोशिश / अंत में संलग्न करें)

latch.countDown();

3
वहाँ 4 कार्य नहीं हैं। एक समय में 4 किए गए "कुछ कार्यों की संख्या" है।
क्लेटस

2
क्षमा करें, मैंने प्रश्न को गलत समझा। हां, कार्य की संख्या काउंटडाउन लैंथ कंस्ट्रक्टर का तर्क होना चाहिए
ChssPly76

3
मुझे यह समाधान दूसरों की तुलना में अधिक सुंदर लगता है, ऐसा लगता है कि यह इस उद्देश्य के लिए बनाया गया था, और यह सरल और सीधा है।
wvdschel

3
क्या होगा यदि आप शुरू करने से पहले कार्यों की संख्या नहीं जानते हैं?
क्लेटस

11
@ क्लेटस - तब आप एक काउंटडाउनचैट का उपयोग नहीं करते हैं। :-) आप पर ध्यान दें, मैं यह तर्क नहीं दे रहा हूं कि यह दृष्टिकोण आपसे बेहतर है। हालांकि, मैंने पाया है कि वास्तविक जीवन स्थितियों में मैं करते कार्यों की संख्या पता है, थ्रेड पूल सेटिंग्स करते तैनाती प्रति विन्यास होने की जरूरत है, और पूल कर सकते हैं पुनः उपयोग किया जा। तो मैं आमतौर पर धागा पूल स्प्रिंग द्वारा इंजेक्शन और उन्हें प्रोटोटाइप के रूप में स्थापित करने और उन्हें मैन्युअल रूप से बंद करने के लिए नीचे है केवल क्रम में समाप्त करने के लिए सूत्र के लिए प्रतीक्षा करने के लिए आदर्श की तुलना में कम लगता है।
ChssPly76

82

ExecutorService.invokeAll() आपके लिए करता है।

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

कठिनाई तब आती है जब / जब आपके पास "4" के धागे एक समय में शुरू होते हैं, तो टुकड़ा-वार, फिर
सम्मिलित

@rogerdpack: मैं अभी भी इस निष्पादक और सामान को सीख रहा हूं। लेकिन आप जो मांगते हैं, उसके जवाब में। क्या एक समय में 4 सूत्र एक बैच कार्य का हिस्सा नहीं होना चाहिए जिसे ऊपर दिए गए उत्तर का उपयोग करके निष्पादित किया जाता है?
मुकुल गोयल

3
यह विधि केवल तभी काम करेगी जब आप हाथ से पहले कार्यों की संख्या जानते हैं।
Konstantin

3
मुझे लगता है कि जब futuresवापस आ जाते हैं, तो कार्य पूरा नहीं हुआ है। वे भविष्य में पूरा कर सकते हैं और आपके पास परिणाम के लिए एक लिंक होगा। इसलिए इसे ए कहते हैं Future। आपके पास Future.get () विधि है , जो परिणाम प्राप्त करने के लिए कार्य के समाप्त होने की प्रतीक्षा करेगी।
11:46 बजे AlikElzin-kilaka

5
JavaDocs से @ AlikElzin-kilaka उद्धरण (उत्तर में जुड़ा हुआ है): "दिए गए कार्यों को निष्पादित करता है, सभी पूर्ण होने पर अपनी स्थिति और परिणामों को पकड़े हुए फ्यूचर्स की सूची लौटाता है। लौटे सूची के प्रत्येक तत्व के लिए Future.isDone () सही है। "
हल्क

47

आप फ्यूचर्स की सूचियों का उपयोग कर सकते हैं, साथ ही:

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

फिर जब आप उन सभी में शामिल होना चाहते हैं, तो अनिवार्य रूप से प्रत्येक पर जुड़ने के बराबर है, (अतिरिक्त लाभ के साथ कि यह बच्चे के धागे से मुख्य तक अपवादों को फिर से उठाता है):

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

मूल रूप से ट्रिक को कॉल करना है। प्रत्येक (एक या एक बार) पर अनन्त लूपिंग कॉलिंग के बजाय। तो आप अंतिम थ्रेड खत्म होते ही इस ब्लॉक को "आगे और पीछे" चलने की गारंटी देते हैं। कैविएट यह है कि चूंकि .get () कॉल अपवादों को फिर से उठाता है, यदि थ्रेड्स में से एक की मृत्यु हो जाती है, तो आप संभवतः इस से उठाते हैं इससे पहले कि अन्य थ्रेड्स पूरा होने से पहले समाप्त हो जाएं [इससे बचने के लिए, आप catch ExecutionExceptionकॉल प्राप्त कर सकते हैं। ]। अन्य चेतावनी यह है कि यह सभी थ्रेड्स के लिए एक संदर्भ रखता है इसलिए यदि उनके पास थ्रेड लोकल वैरिएबल हैं जो आपको इस ब्लॉक को प्राप्त करने के बाद एकत्र नहीं होंगे (हालाँकि आप इसे प्राप्त करने में सक्षम हो सकते हैं, यदि यह समस्या बन गई है, इसे हटाकर भविष्य के बंद ArrayList)। यदि आप जानना चाहते हैं कि कौन सा भविष्य "पहले खत्म" होगाhttps://stackoverflow.com/a/31885029/32453


3
यह जानने के लिए कि कौन सा "पहले खत्म" होता है, का उपयोग करें ExecutorCompletionService.take: stackoverflow.com/a/11872604/199364
टूलमेकर

34

Java8 में आप के साथ यह कर सकते हैं CompletableFuture :

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
यह एक बहुत ही सुंदर समाधान है।
22

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 () के बाद आवश्यक है?
गौरव

@gaurav जब आप शटडाउन कहते हैं, तो कुछ कार्य अभी तक समाप्त नहीं हो सकते हैं। इसलिए जब तक सब कुछ नहीं हो जाता तब तक वाट्सएप कॉलिंग थ्रेड को ब्लॉक करेगा। यह इस बात पर निर्भर करता है कि आपको इस धागे में परिणामों की प्रतीक्षा करने की आवश्यकता है या नहीं।
एडमस्काइल्कर

@AdamSkywalker शानदार जवाब। अगर मैं परिणामों के लिए प्रतीक्षा करने की आवश्यकता नहीं है, तो मुझे कॉल नहीं करना चाहिए।
गौरव

26

केवल मेरे दो सेंट्स। CountDownLatchपहले से कार्यों की संख्या को जानने की आवश्यकता को दूर करने के लिए, आप इसे एक साधारण तरीके से उपयोग करके पुराने तरीके से कर सकते हैं Semaphore

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

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

अपने कार्य में s.release()जैसा आप कहेंगे वैसा ही करेंlatch.countDown();


यह देखते हुए, मैंने पहले सोचा कि अगर releaseकॉल से पहले कुछ कॉल होते हैं तो यह एक समस्या होगी acquire, लेकिन सेमीफोर प्रलेखन को पढ़ने के बाद, मुझे लगता है कि ठीक है।
टूलमेकरसैट

13

खेल के लिए थोड़ा देर से लेकिन पूरा होने के लिए ...

सभी कार्यों को पूरा करने के लिए 'प्रतीक्षा' के बजाय, आप हॉलीवुड के सिद्धांत के संदर्भ में सोच सकते हैं, "मुझे कॉल न करें, मैं आपको कॉल करूंगा" - जब मैं समाप्त कर लूंगा। मुझे लगता है कि परिणामी कोड अधिक सुरुचिपूर्ण है ...

अमरूद इसे पूरा करने के लिए कुछ दिलचस्प उपकरण प्रदान करता है।

एक उदाहरण ::

एक ExecutorService को एक ListeningExecutorService में लपेटें ::

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

निष्पादन के लिए कॉलबल्स का एक संग्रह प्रस्तुत करें ::

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

अब आवश्यक हिस्सा:

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

सभी का वायदा पूरा होने पर, सुने जाने योग्य सुने जाने के लिए कॉलबैक संलग्न करें।

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

यह भी लाभ प्रदान करता है कि प्रसंस्करण समाप्त होने के बाद आप सभी परिणाम एक ही स्थान पर एकत्र कर सकते हैं ...

अधिक जानकारी यहाँ


2
बहुत साफ। एंड्रॉइड पर भी निर्दोष रूप से काम करता है। बस में उपयोग करना runOnUiThread()था onSuccess()
DSchmidt

12

CyclicBarrier जावा 5 में और बाद में कक्षा बात की इस तरह के लिए बनाया गया है।


7
कूल, इस डेटा संरचना का नाम कभी याद नहीं रख सकता है। हालांकि, केवल तभी उपयुक्त है जब आप पहले से जानते हैं कि कार्यों की मात्रा कितनी होगी।
8: ᆼ

हाँ, आपको लगता है कि आप वर्तमान धागे और सभी बच्चे धागे के साथ बाधा को मारने में सक्षम होंगे, फिर जब आप इसे पारित करेंगे तो आपको पता चलेगा कि बच्चे धागे थे ...
22

दरअसल यह गलत उत्तर है। CyclicBarrier भागों के लिए डिज़ाइन किया गया।
CountDownLatch

7

नीचे दिए गए तरीकों में से एक का पालन करें।

  1. दोहराएं सभी के माध्यम से भविष्य कार्य, से लौटे submitपर ExecutorServiceकॉल को अवरुद्ध साथ और स्थिति की जांच get()पर Futureके रूप में द्वारा सुझाए गए वस्तुKiran
  2. ExecutorServiceinvokeAll() पर उपयोग करें
  3. CountDownLatch
  4. ForkJoinPool या Executors.html # newWorkStealingPool
  5. shutdown, awaitTermination, shutdownNowउचित क्रम में ThreadPoolExecutor के API का उपयोग करें

संबंधित एसई प्रश्न:

जावा मल्टीथ्रेडिंग में काउंटडाउन लॉच का उपयोग कैसे किया जाता है?

कैसे ठीक से जावा ExecutorService बंद करने के लिए


6

यहां दो विकल्प हैं, बस थोड़ा भ्रमित करें कि कौन सा जाना सबसे अच्छा है।

विकल्प 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();

विकल्प 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();

यहाँ भविष्य डालना। (); कोशिश में पकड़ सही विचार है?


5

आप अपने कार्यों को एक और चलाने योग्य में लपेट सकते हैं, जो सूचनाएं भेजेंगे:

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

1
मुझे यह देखने के लिए थोड़ी देर लगी कि यह ओपी के सवाल को कैसे हल करेगा। सबसे पहले, ध्यान दें कि यह रैपिंग प्रत्येक कार्य की है, उस कोड की नहीं जो सभी कार्यों को शुरू करता है। मुमकिन है, प्रत्येक शुरू एक काउंटर बढ़ाना होगा, और प्रत्येक खत्म होगा कि काउंटर, या एक completedकाउंटर वृद्धि होगी । इसलिए उन सभी को शुरू करने के बाद, प्रत्येक अधिसूचना पर, यह निर्धारित कर सकता है कि सभी कार्य पूरे हो गए हैं या नहीं। ध्यान दें कि इसका उपयोग करना महत्वपूर्ण है try/finallyताकि catchकिसी कार्य के विफल होने पर भी एक समाप्त अधिसूचना (या ब्लॉक में एक वैकल्पिक अधिसूचना ) दी जाए। अन्यथा, हमेशा के लिए इंतजार करेंगे।
टूलमेकरसैट

3

मैंने सिर्फ एक नमूना कार्यक्रम लिखा है जो आपकी समस्या को हल करता है। कोई संक्षिप्त कार्यान्वयन नहीं दिया गया था, इसलिए मैं एक जोड़ूंगा। जब आप उपयोग कर सकते हैं executor.shutdown()और executor.awaitTermination(), यह सबसे अच्छा अभ्यास नहीं है क्योंकि विभिन्न थ्रेड्स द्वारा लिया गया समय अप्रत्याशित होगा।

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

यह अच्छा है कि आप भविष्य के उपयोग को दिखाएं। इसके बारे में जानने के लिए अच्छा विकल्प। लेकिन कुछ अधिकतम स्वीकार्य समय निर्धारित करने की तुलना में आप हमेशा के लिए इंतजार करना बेहतर क्यों मानते हैं ? इससे भी महत्वपूर्ण बात, यह सब तर्क करने का कोई कारण नहीं है, जब कोई बस प्रतीक्षा करने के लिए वास्तव में बहुत लंबा समय दे सकता है, यदि आप सभी कार्यों को पूरा होने तक इंतजार करना चाहते हैं (अनिवार्य रूप से हमेशा के लिए)।
टूलमेकरसैट

यह यहां पहले से प्रस्तुत समाधानों से अलग नहीं है। आपका एकमात्र समाधान @sjlee
pulp_fiction

यह निश्चित नहीं है कि आपको ऑर्कल डॉक के अनुसार जांच करने की आवश्यकता क्यों है, invokeAll केवल तभी वापस आएगा "जब सभी पूर्ण या समय समाप्त हो जाए, जो भी पहले हो"
मशरूर

3

बस कुंडी / बाधाओं का उपयोग करने के लिए यहां और अधिक विकल्प प्रदान करने के लिए अलग है। जब तक कि सभी कंप्लीटेशन सर्विस का उपयोग नहीं कर लेते, तब तक आप आंशिक परिणाम प्राप्त कर सकते हैं ।

व्यवहार में जावा कॉनएरेबिलिटी से: "यदि आपके पास एक्सक्यूसर को जमा करने के लिए गणनाओं का एक बैच है और आप उपलब्ध होने के साथ उनके परिणाम प्राप्त करना चाहते हैं, तो आप प्रत्येक कार्य से जुड़े भविष्य को बनाए रख सकते हैं और बार-बार कॉल करके पूरा करने के लिए मतदान कर सकते हैं। शून्य का टाइमआउट। यह संभव है, लेकिन थकाऊ । सौभाग्य से एक बेहतर तरीका है : एक पूर्ण सेवा। "

यहाँ कार्यान्वयन

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

यह मेरा समाधान है, "एडमस्किवल्कर" टिप पर आधारित है, और यह काम करता है

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

आप इस कोड का उपयोग कर सकते हैं:

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

मैंने निम्नलिखित कार्य उदाहरण बनाया है। यह विचार है कि कई थ्रेड्स के साथ कार्यों के एक पूल को संसाधित करने का एक तरीका है (मैं उदाहरण के रूप में एक कतार का उपयोग कर रहा हूं) (क्रमादेशिक रूप से संख्या / थ्रेशोल्ड द्वारा निर्धारित), और तब तक प्रतीक्षा करें जब तक कि सभी थ्रेड कुछ अन्य प्रसंस्करण के साथ जारी रखने के लिए पूरा न हो जाएं।

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

आशा है ये मदद करेगा!


1

आप की अपनी खुद की उपवर्ग इस्तेमाल कर सकते हैं ExecutorCompletionService रैप करने के लिए taskExecutor, और की अपनी खुद की कार्यान्वयन BlockingQueue सूचित जब प्रत्येक कार्य को पूरा करता करने के लिए और जो कुछ भी कॉलबैक या अन्य कार्रवाई आप इच्छा जब पूर्ण हो चुके कार्यों की संख्या अपने इच्छित लक्ष्य तक पहुँच जाता है प्रदर्शन करते हैं।


1

आपको उपयोग executorService.shutdown()और executorService.awaitTerminationविधि करनी चाहिए ।

एक उदाहरण इस प्रकार है:

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

}

है इंतजार () शटडाउन के बाद आवश्यक () /
गौरव

1

तो मैं यहाँ से जुड़े प्रश्न से अपना उत्तर पोस्ट करता हूँ, अगर कोई ऐसा करने के लिए एक सरल तरीका चाहता है

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

जावा 8 - हम स्ट्रीम को प्रोसेस करने के लिए स्ट्रीम एपीआई का उपयोग कर सकते हैं। कृपया नीचे स्निपेट देखें

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
हाय व्लादिमीर, स्टैकऑवरफ्लो में आपका स्वागत है। क्या आप यह समझाने के लिए अपने उत्तर को संपादित कर सकते हैं कि यह प्रश्न का उत्तर कैसे देता है, और कोड क्या करता है? कोड केवल उत्तर यहाँ हतोत्साहित किया जाता है। धन्यवाद!
टिम मेलोन

यह पोस्ट कॉन्सेप्ट के बारे में बात करती है। समानांतरवाद! = संगामिति
गेब्रियलबी

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()कुछ अन्य अपवादों को फेंक दें, तो latch.countDown()लगता है कि अमल नहीं होगा, तो मुझे क्या करना चाहिए?


0

यदि आप अधिक थ्रेड एक्सक्यूशन सर्विसेज़ का उपयोग करते हैं और पूरी तरह से समाप्त होने के लिए हर किसी का इंतजार करना चाहते हैं। सबसे अच्छा तरीका नीचे की तरह है;

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

यह मदद कर सकता है

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

आप इस धावक वर्ग पर WaitTillDone () कॉल कर सकते हैं :

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

आप इस वर्ग का पुन: उपयोग कर सकते हैं और प्रतीक्षाटीलडोन () को जितनी बार भी बंद करने से पहले कॉल करना चाहते हैं) () कॉल कर सकते हैं, साथ ही आपका कोड अत्यधिक सरल है । इसके अलावा, आप कार्यों की संख्या को जानने की जरूरत नहीं है

इसका उपयोग करने के लिए बस इस gradle / maven को जोड़ें compile 'com.github.matejtymes:javafixes:1.3.1' अपनी परियोजना में निर्भरता को ।

अधिक विवरण यहां मिल सकता है:

https://github.com/MatejTymes/JavaFixes


-2

निष्पादक में एक विधि है getActiveCount()- जो सक्रिय धागे की गिनती देता है।

धागे को फैलाने के बाद, हम जांच सकते हैं कि क्या activeCount()मूल्य है 0। एक बार मूल्य शून्य होने के बाद, इसका मतलब है कि वर्तमान में कोई सक्रिय थ्रेड नहीं चल रहे हैं जिसका अर्थ है कि कार्य समाप्त हो गया है:

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

3
एक अच्छा विचार नहीं है, देखें stackoverflow.com/a/7271685/1166992 और javadoc: "सक्रिय रूप से कार्य निष्पादित करने वाले थ्रेड्स की अनुमानित संख्या देता है।"
ओलिवियर फौचेक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.