Java Language
एक्ज़ीक्यूटर, एक्ज़ीक्यूसर सर्विस और थ्रेड पूल
खोज…
परिचय
Java में एक्ज़ीक्यूशनर इंटरफ़ेस यांत्रिकी का एक प्रकार से डिकम्प्लिंग टास्क सबमिशन प्रदान करता है कि कैसे प्रत्येक कार्य को चलाया जाएगा, जिसमें थ्रेड उपयोग, शेड्यूलिंग आदि का विवरण शामिल है। एक्सक्यूसर का उपयोग आमतौर पर थ्रेड बनाने के बजाय स्पष्ट रूप से किया जाता है। एक्ज़ीक्यूटर्स के साथ, डेवलपर्स को अपने प्रोग्राम की कार्य-निष्पादन नीति को आसानी से ट्यून करने में सक्षम होने के लिए अपने कोड को फिर से लिखना होगा।
टिप्पणियों
नुकसान
- जब आप बार-बार निष्पादन के लिए किसी कार्य को शेड्यूल करते हैं, तो शेड्यूल किए गए शेड्यूल किए गए शेड्यूल के आधार पर, आपके कार्य को किसी भी और निष्पादन से निलंबित किया जा सकता है, यदि आपके कार्य का निष्पादन एक अपवाद का कारण बनता है जिसे संभाला नहीं गया है। Mother F ** k को शेड्यूल्ड एक्सक्लूसर सर्विस देखें !
आग और भूल - Runnable कार्य
निष्पादनकर्ता एक java.lang.Runnable
स्वीकार करते java.lang.Runnable
जिसमें (संभावित रूप से कम्प्यूटेशनल या अन्यथा लंबे समय तक चलने वाले या भारी) कोड को दूसरे थ्रेड में चलाया जा सकता है।
उपयोग होगा:
Executor exec = anExecutor;
exec.execute(new Runnable() {
@Override public void run() {
//offloaded work, no need to get result back
}
});
ध्यान दें कि इस निष्पादक के साथ, आपके पास किसी भी गणना किए गए मान को वापस पाने का कोई साधन नहीं है।
जावा 8 के साथ, कोई कोड उदाहरण को छोटा करने के लिए लैम्ब्डा का उपयोग कर सकता है।
Executor exec = anExecutor;
exec.execute(() -> {
//offloaded work, no need to get result back
});
ThreadPoolExecutor
एक सामान्य एक्सक्यूजर का उपयोग ThreadPoolExecutor
, जो थ्रेड हैंडलिंग का ध्यान रखता है। आप थ्रेड्स की न्यूनतम मात्रा को हमेशा कॉन्फ़िगर कर सकते हैं जब हमेशा ऐसा करना पड़ता है, तो ऐसा करने के लिए बहुत कुछ नहीं है (इसे कोर आकार कहा जाता है) और एक अधिकतम थ्रेड आकार, जिससे पूल विकसित हो सकता है, अगर वहाँ अधिक काम करना है। एक बार जब वर्कलोड कम हो जाता है, तो पूल धीरे-धीरे थ्रेड काउंट को फिर से कम कर देता है जब तक कि यह न्यूनतम आकार तक नहीं पहुंच जाता।
ThreadPoolExecutor pool = new ThreadPoolExecutor(
1, // keep at least one thread ready,
// even if no Runnables are executed
5, // at most five Runnables/Threads
// executed in parallel
1, TimeUnit.MINUTES, // idle Threads terminated after one
// minute, when min Pool size exceeded
new ArrayBlockingQueue<Runnable>(10)); // outstanding Runnables are kept here
pool.execute(new Runnable() {
@Override public void run() {
//code to run
}
});
नोट आप कॉन्फ़िगर करते हैं ThreadPoolExecutor
एक असीम कतार के साथ है, तो धागा गिनती से अधिक नहीं होगा corePoolSize
के बाद से नए सूत्र केवल तभी कतार भर गई है बनाई गई हैं:
सभी मापदंडों के साथ ThreadPoolExecutor:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
यदि कोरपूलसाइज़ से अधिक हैं लेकिन अधिकतम चलने वाले थ्रेड्स से कम चल रहे हैं, तो एक नया धागा केवल तभी बनाया जाएगा जब कतार भरी हो।
लाभ:
ब्लॉकिंग क्यू आकार को नियंत्रित किया जा सकता है और स्मृति परिदृश्यों से बचा जा सकता है। अनुप्रयोग प्रदर्शन सीमित सीमित कतार आकार के साथ नीचा नहीं होगा।
आप मौजूदा का उपयोग कर सकते हैं या नई अस्वीकृति हैंडलर नीतियां बना सकते हैं।
डिफ़ॉल्ट थ्रेडपूलExecutor.AbortPolicy में, हैंडलर अस्वीकृति पर एक रनटाइम RejectExecutionException फेंकता है।
ThreadPoolExecutor.CallerRunsPolicy
, जिस थ्रेड को कार्यान्वित करता है वह कार्य चलाता है। यह एक सरल प्रतिक्रिया नियंत्रण तंत्र प्रदान करता है जो नए कार्यों को प्रस्तुत करने की दर को धीमा कर देगा।ThreadPoolExecutor.DiscardPolicy
, एक कार्य जिसे निष्पादित नहीं किया जा सकता है, बस गिरा दिया जाता है।ThreadPoolExecutor.DiscardOldestPolicy
, यदि निष्पादक को बंद नहीं किया जाता है, तो कार्य कतार के शीर्ष पर स्थित कार्य हटा दिया जाता है, और फिर निष्पादन वापस ले लिया जाता है (जो फिर से विफल हो सकता है, जिससे यह दोहराया जा सकता है)
कस्टम
ThreadFactory
को कॉन्फ़िगर किया जा सकता है, जो उपयोगी है:- अधिक वर्णनात्मक थ्रेड नाम सेट करने के लिए
- थ्रेड डेमॉन स्थिति सेट करने के लिए
- धागा प्राथमिकता निर्धारित करने के लिए
यहाँ एक उदाहरण है कि कैसे ThreadPoolExecutor का उपयोग किया जाए
गणना से पुनः प्राप्त मूल्य - कॉल करने योग्य
यदि आपकी गणना कुछ रिटर्न वैल्यू पैदा करती है जो बाद में आवश्यक है, तो एक साधारण रननेबल कार्य पर्याप्त नहीं है। ऐसे मामलों के लिए आप ExecutorService.submit(
Callable
<T>)
उपयोग कर सकते हैं जो निष्पादन पूर्ण होने के बाद एक मान लौटाता है।
सेवा एक Future
जिसका उपयोग आप कार्य निष्पादन के परिणाम को प्राप्त करने के लिए कर सकते हैं।
// Submit a callable for execution
ExecutorService pool = anExecutorService;
Future<Integer> future = pool.submit(new Callable<Integer>() {
@Override public Integer call() {
//do some computation
return new Random().nextInt();
}
});
// ... perform other tasks while future is executed in a different thread
जब आपको भविष्य का परिणाम प्राप्त करने की आवश्यकता हो, तो future.get()
कॉल करें future.get()
परिणाम के साथ भविष्य के लिए अनिश्चित काल तक प्रतीक्षा करें।
try { // Blocks current thread until future is completed Integer result = future.get(); catch (InterruptedException || ExecutionException e) { // handle appropriately }
भविष्य के समाप्त होने की प्रतीक्षा करें, लेकिन निर्दिष्ट समय से अधिक नहीं।
try { // Blocks current thread for a maximum of 500 milliseconds. // If the future finishes before that, result is returned, // otherwise TimeoutException is thrown. Integer result = future.get(500, TimeUnit.MILLISECONDS); catch (InterruptedException || ExecutionException || TimeoutException e) { // handle appropriately }
यदि अनुसूचित या चालू कार्य के परिणाम की आवश्यकता नहीं है, तो आप इसे रद्द करने के लिए Future.cancel(boolean)
को कॉल कर सकते हैं।
-
cancel(false)
कॉलcancel(false)
कार्य को चलाने के लिए कार्य की कतार से हटा देगा। - यदि यह वर्तमान में चल रहा है तो कॉल
cancel(true)
कार्य को भी बाधित करेगा।
एक देरी या बार-बार के बाद, एक निश्चित समय पर चलने के लिए शेड्यूलिंग कार्य
ScheduledExecutorService
वर्ग कई तरीकों से एकल या बार-बार कार्य शेड्यूल करने के लिए एक विधि प्रदान करता है। निम्न कोड नमूना मान लेता है कि pool
घोषित किया गया है और निम्नानुसार आरंभ किया गया है:
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
सामान्य ExecutorService
विधियों के अतिरिक्त, ScheduledExecutorService
API 4 विधियों को जोड़ता है जो कार्यों को शेड्यूल करता है और ScheduledFuture
ऑब्जेक्ट को वापस करता है। उत्तरार्द्ध का उपयोग परिणाम प्राप्त करने के लिए किया जा सकता है (कुछ मामलों में) और कार्यों को रद्द करने के लिए।
एक निश्चित देरी के बाद एक कार्य शुरू करना
निम्न उदाहरण दस मिनट के बाद शुरू करने के लिए एक कार्य को निर्धारित करता है।
ScheduledFuture<Integer> future = pool.schedule(new Callable<>() {
@Override public Integer call() {
// do something
return 42;
}
},
10, TimeUnit.MINUTES);
निश्चित दर पर कार्य शुरू करना
निम्न उदाहरण दस मिनट के बाद शुरू करने के लिए एक कार्य को निर्धारित करता है, और फिर हर एक मिनट में एक बार की दर से।
ScheduledFuture<?> future = pool.scheduleAtFixedRate(new Runnable() {
@Override public void run() {
// do something
}
},
10, 1, TimeUnit.MINUTES);
टास्क निष्पादन शेड्यूल के अनुसार जारी रहेगा, जब तक कि pool
बंद नहीं हो जाता, future
रद्द हो जाता है, या कार्यों में से एक अपवाद का सामना करता है।
यह गारंटी दी जाती है कि किसी scheduledAtFixedRate
कॉल द्वारा निर्धारित कार्य समय में ओवरलैप नहीं होंगे। यदि कोई कार्य निर्धारित अवधि से अधिक समय लेता है, तो अगले और बाद के कार्य निष्पादन देर से शुरू हो सकते हैं।
निश्चित देरी से कार्य शुरू करना
निम्नलिखित उदाहरण दस मिनट के बाद शुरू करने के लिए एक कार्य को निर्धारित करता है, और फिर एक कार्य के समाप्त होने और अगले एक के शुरू होने के बीच एक मिनट की देरी के साथ बार-बार।
ScheduledFuture<?> future = pool.scheduleWithFixedDelay(new Runnable() {
@Override public void run() {
// do something
}
},
10, 1, TimeUnit.MINUTES);
टास्क निष्पादन शेड्यूल के अनुसार जारी रहेगा, जब तक कि pool
बंद नहीं हो जाता, future
रद्द हो जाता है, या कार्यों में से एक अपवाद का सामना करता है।
हैंडल रिजेक्टेड एक्जीक्यूशन
अगर
- आप किसी शटडाउन एक्सेक्यूटर या करने के लिए कार्य प्रस्तुत करने का प्रयास करें
- कतार संतृप्त है (केवल बाउंडेड लोगों के साथ संभव है) और अधिकतम संख्या में थ्रेड्स तक पहुंच गया है,
RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor)
कहा जाएगा।
डिफ़ॉल्ट व्यवहार यह है कि आपको कॉलर पर एक RejectExecutionException फेंक दिया जाएगा। लेकिन वहाँ अधिक पूर्वनिर्धारित व्यवहार उपलब्ध हैं:
- ThreadPoolExecutor.AbortPolicy (डिफ़ॉल्ट, REE फेंक देगा)
- ThreadPoolExecutor.CallerRunsPolicy (कॉलर के थ्रेड पर कार्य निष्पादित करता है - इसे अवरुद्ध करना )
- ThreadPoolExecutor.DiscardPolicy (चुपचाप काम छोड़ दें)
- ThreadPoolExecutor.DiscardOldestPolicy (कतार में सबसे पुराने कार्य को छोड़ दें और नए कार्य को फिर से निष्पादित करें)
आप उन्हें थ्रेडपूल निर्माणकर्ताओं में से एक का उपयोग करके सेट कर सकते हैं:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) // <--
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) // <--
आप RejectExecutionHandler इंटरफ़ेस का विस्तार करके अपने स्वयं के व्यवहार को लागू कर सकते हैं:
void rejectedExecution(Runnable r, ThreadPoolExecutor executor)
सबमिट () बनाम निष्पादित () अपवाद हैंडलिंग मतभेद
आम तौर पर निष्पादित () कमांड का उपयोग आग और भूल कॉल (परिणाम का विश्लेषण करने की आवश्यकता के बिना) और सबमिट () कमांड का उपयोग फ्यूचर ऑब्जेक्ट के परिणाम का विश्लेषण करने के लिए किया जाता है।
हमें इन दोनों आदेशों के बीच अपवाद संचालन तंत्र के प्रमुख अंतर के बारे में पता होना चाहिए।
यदि आपने उन्हें नहीं पकड़ा है, तो सबमिट () से अपवाद फ्रेमवर्क द्वारा निगला जाता है।
अंतर समझने के लिए कोड उदाहरण:
केस 1: निष्पादित के साथ रननेबल को सबमिट करें () कमांड, जो अपवाद की रिपोर्ट करता है।
import java.util.concurrent.*;
import java.util.*;
public class ExecuteSubmitDemo {
public ExecuteSubmitDemo() {
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(2);
//ExtendedExecutor service = new ExtendedExecutor();
for (int i = 0; i < 2; i++){
service.execute(new Runnable(){
public void run(){
int a = 4, b = 0;
System.out.println("a and b=" + a + ":" + b);
System.out.println("a/b:" + (a / b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
}
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
class ExtendedExecutor extends ThreadPoolExecutor {
public ExtendedExecutor() {
super(1, 1, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
}
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}
उत्पादन:
creating service
a and b=4:0
a and b=4:0
Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2" java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:15)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
केस 2: सबमिट () के साथ निष्पादित () बदलें: service.submit(new Runnable(){
उत्पादन:
creating service
a and b=4:0
a and b=4:0
केस 3: newFixedThreadPool को ExtendedExecutor में बदलें
//ExecutorService service = Executors.newFixedThreadPool(2);
ExtendedExecutor service = new ExtendedExecutor();
उत्पादन:
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
a and b=4:0
java.lang.ArithmeticException: / by zero
मैंने दो विषयों को कवर करने के लिए इस उदाहरण का प्रदर्शन किया है: अपने कस्टम थ्रेडपूल एक्ज़ीक्यूटर का उपयोग करें और कस्टम थ्रेडपूल एक्सपोर्टर के साथ एक्सपेप्शन को संभालें।
उपरोक्त समस्या का अन्य सरल समाधान: जब आप सामान्य एक्ज़ीक्यूसर सर्विस एंड कमांड सबमिट कर रहे हों, तो फ्यूचर ऑब्जेक्ट को सबमिट () कमांड कॉल गेट () एपीआई ऑन फ़्यूचर से प्राप्त करें। तीन अपवादों को पकड़ें, जिन्हें afterExecute विधि कार्यान्वयन में उद्धृत किया गया है। इस दृष्टिकोण पर कस्टम थ्रेडपूल एक्ज़ीक्यूटर का लाभ: आपको केवल एक ही स्थान पर एक्सेप्शन हैंडलिंग तंत्र को संभालना होगा - कस्टम थ्रेडपूल एक्सपोर्टर।
विभिन्न प्रकार के कंसीडर कंस्ट्रक्शन के मामलों का उपयोग करें
ExecutorService executor = Executors.newFixedThreadPool(50);
यह सरल और प्रयोग करने में आसान है। यह
ThreadPoolExecutor
निम्न स्तर के विवरण को छुपाता है।मैं इसे पसंद करता हूं जब
Callable/Runnable
करने योग्यCallable/Runnable
करने योग्य कार्यों की संख्या संख्या में छोटी होती है और बिना कतार में कार्यों के जमाव स्मृति को बढ़ाती नहीं है और सिस्टम के प्रदर्शन को नीचा दिखाती है। यदि आपके पासCPU/Memory
बाधाएं हैं, तो मैं कार्यों कीRejectedExecutionHandler
को संभालने के लिए क्षमता की कमी औरRejectedExecutionHandler
ThreadPoolExecutor
साथThreadPoolExecutor
का उपयोग करना पसंद करता हूं।CountDownLatch
एक दिए गए गिनती के साथ आरंभ किया जाएगा। इस गणना कोcountDown()
विधि से कॉल द्वारा घटाया जाता है। इस गिनती के शून्य तक पहुंचने की प्रतीक्षा कर रहे थ्रेड प्रतीक्षाawait()
विधियों में से एक कह सकते हैं। कॉलिंगawait()
थ्रेड को ब्लॉक करता है जब तक कि गिनती शून्य तक नहीं पहुंच जाती। यह वर्ग एक जावा थ्रेड को तब तक प्रतीक्षा करने में सक्षम बनाता है जब तक कि थ्रेड्स का अन्य सेट अपने कार्यों को पूरा नहीं करता है।बक्सों का इस्तेमाल करें:
अधिकतम समानता प्राप्त करना: कभी-कभी हम अधिकतम समानता प्राप्त करने के लिए एक ही समय में कई सूत्र शुरू करना चाहते हैं
निष्पादन शुरू करने से पहले एन धागे को पूरा करें
गतिरोध का पता लगाने।
ThreadPoolExecutor : यह अधिक नियंत्रण प्रदान करता है। यदि अनुप्रयोग लंबित Runnable / Callable कार्यों की संख्या से विवश है, तो आप अधिकतम क्षमता निर्धारित करके बाध्य कतार का उपयोग कर सकते हैं। एक बार जब कतार अधिकतम क्षमता तक पहुँच जाती है, तो आप अस्वीकृति को परिभाषित कर सकते हैं। जावा चार प्रकार की
RejectedExecutionHandler
नीतियाँ प्रदान करता है।ThreadPoolExecutor.AbortPolicy
, हैंडलर अस्वीकृति पर एक रनटाइम RejectExecutionException फेंकता है।ThreadPoolExecutor.CallerRunsPolicy`, खुद को निष्पादित करने वाला धागा कार्य चलाता है। यह एक सरल प्रतिक्रिया नियंत्रण तंत्र प्रदान करता है जो नए कार्यों को प्रस्तुत करने की दर को धीमा कर देगा।
ThreadPoolExecutor.DiscardPolicy
, एक कार्य जिसे निष्पादित नहीं किया जा सकता है, बस गिरा दिया जाता है।ThreadPoolExecutor.DiscardOldestPolicy
, यदि निष्पादक को बंद नहीं किया जाता है, तो कार्य कतार के प्रमुख पर कार्य छोड़ दिया जाता है, और फिर निष्पादन वापस ले लिया जाता है (जो फिर से विफल हो सकता है, जिससे यह दोहराया जा सकता है।)
आप अनुकरण करने के लिए चाहते हैं CountDownLatch
व्यवहार, आप उपयोग कर सकते हैं invokeAll()
विधि।
एक और तंत्र जिसे आपने उद्धृत नहीं किया वह है ForkJoinPool
ForkJoinPool
जावा 7 में जावा के लिए जोड़ा गयाForkJoinPool
जावा के समान हैExecutorService
लेकिन एक अंतर के साथ।ForkJoinPool
अपने कार्यों को छोटे कार्यों में विभाजित करना आसान बनाता है जो बाद मेंForkJoinPool
को सबमिट किएForkJoinPool
हैं।ForkJoinPool
में टास्क चोरी तबForkJoinPool
जब मुक्त श्रमिक सूत्र व्यस्त श्रमिक थ्रेड कतार से कार्यों को चोरी करते हैं।जावा 8 ने कार्य चोरी पूल बनाने के लिए एक्जिकोरसेवर में एक और एपीआई पेश किया है। आपको
RecursiveTask
औरRecursiveAction
बनाने की आवश्यकता नहीं है, लेकिन फिर भीForkJoinPool
उपयोग कर सकते हैं।public static ExecutorService newWorkStealingPool()
सभी उपलब्ध प्रोसेसरों को अपने लक्ष्य समानांतरता स्तर के रूप में उपयोग करके एक काम-चोरी धागा पूल बनाता है।
डिफ़ॉल्ट रूप से, यह CPU कोर की संख्या को पैरामीटर के रूप में लेगा।
ये सभी चार तंत्र एक-दूसरे के लिए अनुकूल हैं। दानेदारता के स्तर के आधार पर जिसे आप नियंत्रित करना चाहते हैं, आपको सही लोगों को चुनना होगा।
ExecutorService में सभी कार्यों के पूरा होने की प्रतीक्षा करें
चलिए एक्ज़ीक्यूसर को सौंपे गए कार्यों को पूरा करने के लिए विभिन्न विकल्पों पर एक नज़र डालते हैं
- ExecutorService
invokeAll()
दिए गए कार्यों को निष्पादित करता है, जब सब कुछ पूरा हो जाता है, तो अपनी स्थिति और परिणामों को पकड़े हुए फ्यूचर्स की सूची लौटाते हैं।
उदाहरण:
import java.util.concurrent.*;
import java.util.*;
public class InvokeAllDemo{
public InvokeAllDemo(){
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<MyCallable> futureList = new ArrayList<MyCallable>();
for (int i = 0; i < 10; i++){
MyCallable myCallable = new MyCallable((long)i);
futureList.add(myCallable);
}
System.out.println("Start");
try{
List<Future<Long>> futures = service.invokeAll(futureList);
} catch(Exception err){
err.printStackTrace();
}
System.out.println("Completed");
service.shutdown();
}
public static void main(String args[]){
InvokeAllDemo demo = new InvokeAllDemo();
}
class MyCallable implements Callable<Long>{
Long id = 0L;
public MyCallable(Long val){
this.id = val;
}
public Long call(){
// Add your business logic
return id;
}
}
}
एक सिंक्रनाइज़ेशन सहायता जो एक या अधिक थ्रेड्स को प्रतीक्षा करने की अनुमति देती है जब तक कि अन्य थ्रेड्स में किए गए संचालन का एक सेट पूरा नहीं हो जाता।
एक CountDownLatch एक दिए गए गिनती के साथ शुरू होता है।
countDown()
विधि के इनवोकेशन के कारण करंट काउंट शून्य तक पहुंचने तकcountDown()
तरीके ब्लॉक हो जाते हैं, जिसके बाद सभी वेटिंग थ्रेड जारी होते हैं और वेटिंग के किसी भी बाद के इनवोकेशन तुरंत लौट आते हैं। यह एक-शॉट वाली घटना है - गिनती को रीसेट नहीं किया जा सकता है। यदि आपको एक संस्करण की आवश्यकता है जो गणना को रीसेट करता है, तो एक CyclicBarrier का उपयोग करने पर विचार करें।ForkJoinPool या
newWorkStealingPool()
में निष्पादकोंExecutorService को सबमिट करने के बाद बनाई गई सभी
Future
वस्तुओं के माध्यम सेExecutorService
के दैवज्ञ प्रलेखन पेज से बंद की सिफारिश की जिस तरह से ExecutorService :
void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); }
shutdown():
एक अर्दली शटडाउन शुरू करता है जिसमें पहले सबमिट किए गए कार्यों को निष्पादित किया जाता है, लेकिन कोई नया कार्य स्वीकार नहीं किया जाएगा।shutdownNow():
सभी सक्रिय रूप से निष्पादित कार्यों को रोकने का प्रयास, प्रतीक्षा कार्यों के प्रसंस्करण को रोकता है, और उन कार्यों की सूची देता है जो निष्पादन का इंतजार कर रहे थे।ऊपर दिए गए उदाहरण में, यदि आपके कार्यों को पूरा होने में अधिक समय लग रहा है, तो आप यदि स्थिति को स्थिति में बदल सकते हैं
बदलने के
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
साथ में
while(!pool.awaitTermination(60, TimeUnit.SECONDS)) { Thread.sleep(60000);
}
विभिन्न प्रकार के ExecutorService के मामलों का उपयोग करें
निष्पादकों रिटर्न विशिष्ट जरूरत के लिए खानपान ThreadPools के विभिन्न प्रकार।
public static ExecutorService newSingleThreadExecutor()
एक एक्सक्यूबेटर बनाता है जो एक एकल कतार से बाहर काम कर रहे एक एकल श्रमिक धागे का उपयोग करता है
newFixedThreadPool(1)
औरnewSingleThreadExecutor()
बीच एक अंतर है क्योंकि जावा डॉक्टर बाद के लिए कहता है:अन्यथा समकक्ष newFixedThreadPool (1) के विपरीत, दिए गए निष्पादक को अतिरिक्त थ्रेड्स का उपयोग करने के लिए पुन: कॉन्फ़िगर करने योग्य नहीं होने की गारंटी है।
जिसका अर्थ है कि एक
newFixedThreadPool
को प्रोग्राम द्वारा बाद में पुन: कॉन्फ़िगर किया जा सकता है:((ThreadPoolExecutor) fixedThreadPool).setMaximumPoolSize(10)
यहnewSingleThreadExecutor
लिए संभव नहीं है।बक्सों का इस्तेमाल करें:
- आप एक क्रम में प्रस्तुत कार्यों को निष्पादित करना चाहते हैं।
- आपको अपने सभी अनुरोधों को संभालने के लिए केवल एक थ्रेड की आवश्यकता है
विपक्ष:
- असंबद्ध कतार हानिकारक है
public static ExecutorService newFixedThreadPool(int nThreads)
एक थ्रेड पूल बनाता है जो एक साझा अनबाउंड कतार से काम कर रहे थ्रेड की निश्चित संख्या का पुन: उपयोग करता है। किसी भी बिंदु पर, अधिकांश nhhreads में सक्रिय प्रसंस्करण कार्य होंगे। यदि सभी थ्रेड्स सक्रिय होने पर अतिरिक्त कार्य सबमिट किए जाते हैं, तो वे एक थ्रेड उपलब्ध होने तक कतार में प्रतीक्षा करेंगे
बक्सों का इस्तेमाल करें:
- उपलब्ध कोर का प्रभावी उपयोग।
nThreads
कोRuntime.getRuntime().availableProcessors()
रूप में कॉन्फ़िगर करें।nThreads
Runtime.getRuntime().availableProcessors()
- जब आप तय करते हैं कि धागे की संख्या थ्रेड पूल में एक संख्या से अधिक नहीं होनी चाहिए
विपक्ष:
- असंबद्ध कतार हानिकारक है।
- उपलब्ध कोर का प्रभावी उपयोग।
public static ExecutorService newCachedThreadPool()
एक थ्रेड पूल बनाता है जो आवश्यकतानुसार नए थ्रेड बनाता है, लेकिन जब वे उपलब्ध होते हैं तो पहले निर्मित थ्रेड का फिर से उपयोग करेंगे
बक्सों का इस्तेमाल करें:
- अल्पकालिक अतुल्यकालिक कार्यों के लिए
विपक्ष:
- असंबद्ध कतार हानिकारक है।
- प्रत्येक नया कार्य एक नया थ्रेड तैयार करेगा यदि सभी मौजूदा थ्रेड व्यस्त हैं। यदि कार्य लंबी अवधि ले रहा है, तो अधिक संख्या में थ्रेड्स बनाए जाएंगे, जो सिस्टम के प्रदर्शन को नीचा दिखाएगा। इस मामले में वैकल्पिक:
newFixedThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
एक थ्रेड पूल बनाता है जो किसी दिए गए विलंब के बाद चलने के लिए, या समय-समय पर निष्पादित करने के लिए कमांड शेड्यूल कर सकता है।
बक्सों का इस्तेमाल करें:
- विलंब के साथ आवर्ती घटनाओं को संभालना, जो भविष्य में निश्चित समय पर घटित होगा
विपक्ष:
- असंबद्ध कतार हानिकारक है।
5.
public static ExecutorService newWorkStealingPool()
सभी उपलब्ध प्रोसेसरों को अपने लक्ष्य समांतरता स्तर के रूप में उपयोग करते हुए एक कार्य-चोरी धागा पूल बनाता है
बक्सों का इस्तेमाल करें:
- समस्याओं के प्रकार को विभाजित करने और जीतने के लिए।
- निष्क्रिय धागे का प्रभावी उपयोग। निष्क्रिय धागे व्यस्त थ्रेड्स से कार्यों को चुराते हैं।
विपक्ष:
- अनबाउंड कतार आकार हानिकारक है।
आप इन सभी ExecutorService में एक सामान्य कमियां देख सकते हैं: अनबाउंड कतार। इसे ThreadPoolExecutor के साथ संबोधित किया जाएगा
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
ThreadPoolExecutor
साथ, आप कर सकते हैं
- नियंत्रण थ्रेड पूल आकार गतिशील रूप से
-
BlockingQueue
की क्षमता निर्धारित करें - पंक्ति पूर्ण होने पर
RejectionExecutionHander
परिभाषित करें -
CustomThreadFactory
थ्रेड निर्माण के दौरान कुछ अतिरिक्त कार्यक्षमता जोड़ने के लिए(public Thread newThread(Runnable r)
थ्रेड पूल का उपयोग करना
थ्रेड ताल ज्यादातर बुला उपयोग किया जाता है तरीकों ExecutorService
।
निष्पादन के लिए कार्य प्रस्तुत करने के लिए निम्नलिखित विधियों का उपयोग किया जा सकता है:
तरीका | विवरण |
---|---|
submit | सबमिट किए गए कार्य को निष्पादित करता है और एक भविष्य लौटाता है जिसका उपयोग परिणाम प्राप्त करने के लिए किया जा सकता है |
execute | भविष्य में कुछ समय के लिए कोई रिटर्न मान प्राप्त किए बिना कार्य निष्पादित करें |
invokeAll | कार्यों की सूची निष्पादित करें और फ्यूचर्स की सूची लौटाएं |
invokeAny | सभी को निष्पादित करता है, लेकिन केवल एक का परिणाम है कि सफल रहा है (अपवाद के बिना) |
एक बार जब आप थ्रेड पूल के साथ हो जाते हैं तो आप थ्रेड पूल को समाप्त करने के लिए shutdown()
कॉल कर सकते हैं। यह सभी लंबित कार्यों को निष्पादित करता है। निष्पादित करने के लिए सभी कार्यों की प्रतीक्षा करने के लिए आप awaitTermination
या isShutdown()
चारों ओर लूप कर सकते हैं।