जावा 8 समानांतर स्ट्रीम में कस्टम थ्रेड पूल


398

क्या जावा 8 समानांतर धारा के लिए एक कस्टम थ्रेड पूल निर्दिष्ट करना संभव है ? मैं इसे कहीं भी नहीं ढूंढ सकता।

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

अगर मैं अलग-अलग मॉड्यूल के लिए अलग-अलग थ्रेड पूल का उपयोग नहीं कर सकता हूं, तो इसका मतलब है कि मैं वास्तविक दुनिया की अधिकांश स्थितियों में समानांतर धाराओं का सुरक्षित रूप से उपयोग नहीं कर सकता हूं।

निम्न उदाहरण का प्रयास करें। अलग-अलग थ्रेड्स में निष्पादित कुछ सीपीयू गहन कार्य हैं। कार्य समानांतर धाराओं का लाभ उठाते हैं। पहला कार्य टूट गया है, इसलिए प्रत्येक चरण में 1 सेकंड लगता है (थ्रेड स्लीप द्वारा सिम्युलेटेड)। मुद्दा यह है कि अन्य धागे फंस जाते हैं और टूटे हुए कार्य के समाप्त होने की प्रतीक्षा करते हैं। यह आकस्मिक उदाहरण है, लेकिन एक सर्वलेट ऐप की कल्पना करें और कोई व्यक्ति साझा कांटे में शामिल होने के लिए एक लंबे समय तक चलने वाला कार्य प्रस्तुत करता है।

public class ParallelTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = Executors.newCachedThreadPool();

        es.execute(() -> runTask(1000)); //incorrect task
        es.execute(() -> runTask(0));
        es.execute(() -> runTask(0));
        es.execute(() -> runTask(0));
        es.execute(() -> runTask(0));
        es.execute(() -> runTask(0));


        es.shutdown();
        es.awaitTermination(60, TimeUnit.SECONDS);
    }

    private static void runTask(int delay) {
        range(1, 1_000_000).parallel().filter(ParallelTest::isPrime).peek(i -> Utils.sleep(delay)).max()
                .ifPresent(max -> System.out.println(Thread.currentThread() + " " + max));
    }

    public static boolean isPrime(long n) {
        return n > 1 && rangeClosed(2, (long) sqrt(n)).noneMatch(divisor -> n % divisor == 0);
    }
}

3
कस्टम थ्रेड पूल से आपका क्या तात्पर्य है? एक एकल सामान्य ForkJoinPool है, लेकिन आप हमेशा अपना खुद का ForkJoinPool बना सकते हैं और इसके लिए अनुरोध सबमिट कर सकते हैं।
edharned

7
संकेत: Java Champion Heinz Kabutz एक ही समस्या का निरीक्षण करता है लेकिन और भी बुरे प्रभाव के साथ: सामान्य कांटा के डेडलॉकिंग थ्रेड्स पूल से जुड़ते हैं। देखें javaspecialists.eu/archive/Issue223.html
Peti

जवाबों:


395

वास्तव में एक चाल है कि एक विशिष्ट कांटा-जुड़ने वाले पूल में समानांतर संचालन को कैसे निष्पादित किया जाए। यदि आप इसे फोर्क-जॉइन पूल में एक कार्य के रूप में निष्पादित करते हैं, तो यह वहां रहता है और आम का उपयोग नहीं करता है।

final int parallelism = 4;
ForkJoinPool forkJoinPool = null;
try {
    forkJoinPool = new ForkJoinPool(parallelism);
    final List<Integer> primes = forkJoinPool.submit(() ->
        // Parallel task here, for example
        IntStream.range(1, 1_000_000).parallel()
                .filter(PrimesPrint::isPrime)
                .boxed().collect(Collectors.toList())
    ).get();
    System.out.println(primes);
} catch (InterruptedException | ExecutionException e) {
    throw new RuntimeException(e);
} finally {
    if (forkJoinPool != null) {
        forkJoinPool.shutdown();
    }
}

ट्रिक ForkJoinTask.fork पर आधारित है जो निर्दिष्ट करती है: "पूल में इस कार्य को अतुल्यकालिक रूप से निष्पादित करने के लिए व्यवस्था करता है, यदि वर्तमान कार्य चल रहा है, या लागू हो रहा है या ForkJoinPool.commonPool () का उपयोग नहीं कर रहा है तो InForkJoinPool ()"


20
समाधान पर विवरण यहाँ वर्णित हैं। blog.krecan.net/2014/03/18/…
Lukas

3
लेकिन क्या यह भी निर्दिष्ट किया गया है कि धाराएँ ForkJoinPoolकार्यान्वयन का विवरण है या इसका उपयोग ? प्रलेखन के लिए एक लिंक अच्छा होगा।
निकोलाई

6
@ लुकास स्निपेट के लिए धन्यवाद। मैं जोड़ूंगा कि ForkJoinPoolउदाहरण shutdown()तब होना चाहिए जब किसी थ्रेड लीक से बचने के लिए इसकी कोई आवश्यकता नहीं है। (उदाहरण)
जॉक

5
ध्यान दें कि जावा 8 में एक बग है कि भले ही कस्टम पूल उदाहरण पर कार्य चल रहे हों, फिर भी वे साझा पूल से जोड़े जाते हैं: अभिकलन का आकार सामान्य पूल के अनुपात में रहता है न कि कस्टम पूल का। जावा 10 में तय किया गया था: JDK-8190974
टेरान


192

समानांतर धाराएं डिफ़ॉल्ट का उपयोग करती हैं ForkJoinPool.commonPoolजो डिफ़ॉल्ट रूप से आपके पास प्रोसेसर के रूप में एक थ्रेड कम होता है , जैसा कि लौटाया जाता है Runtime.getRuntime().availableProcessors()(इसका मतलब है कि समानांतर धारा आपके सभी प्रोसेसर का उपयोग करती है क्योंकि वे मुख्य धागे का उपयोग करते हैं):

उन अनुप्रयोगों के लिए जिन्हें अलग या कस्टम पूल की आवश्यकता होती है, एक ForkJoinPool का निर्माण किसी दिए गए लक्ष्य समानतावाद स्तर के साथ किया जा सकता है; डिफ़ॉल्ट रूप से, उपलब्ध प्रोसेसर की संख्या के बराबर।

इसका मतलब यह भी है कि यदि आपने समानांतर धाराएँ या कई समानांतर धाराएँ समवर्ती रूप से शुरू की हैं, तो वे सभी एक ही पूल को साझा करेंगी । लाभ: आप डिफ़ॉल्ट (उपलब्ध प्रोसेसर की संख्या) से अधिक का उपयोग कभी नहीं करेंगे। नुकसान: आपको "सभी प्रोसेसर" नहीं मिल सकते हैं जो आपके द्वारा शुरू की गई प्रत्येक समानांतर धारा को सौंपे जाते हैं (यदि आपके पास एक से अधिक होने के लिए होता है)। (स्पष्ट रूप से आप इसे रोकने के लिए एक ManagedBlocker का उपयोग कर सकते हैं ।)

जिस तरह से समानांतर धाराओं को निष्पादित किया जाता है, उसे बदलने के लिए, आप या तो कर सकते हैं

  • अपने खुद के ForkJoinPool के लिए समानांतर धारा निष्पादन प्रस्तुत करें: yourFJP.submit(() -> stream.parallel().forEach(soSomething)).get();या
  • आप सिस्टम गुणों का उपयोग करके सामान्य पूल का आकार बदल सकते हैं: System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20")20 थ्रेड्स के लक्ष्य समानता के लिए। हालाँकि, अब यह बैकपोटेड पैच https://bugs.openjdk.java.net/browse/JDK-8190974 के बाद काम नहीं करता है ।

मेरी मशीन पर उत्तरार्द्ध का उदाहरण जिसमें 8 प्रोसेसर हैं। यदि मैं निम्नलिखित कार्यक्रम चलाता हूं:

long start = System.currentTimeMillis();
IntStream s = IntStream.range(0, 20);
//System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");
s.parallel().forEach(i -> {
    try { Thread.sleep(100); } catch (Exception ignore) {}
    System.out.print((System.currentTimeMillis() - start) + " ");
});

आउटपुट है:

215 216 216 216 216 216 216 315 316 316 316 316 316 316 415 416 416 416

तो आप देख सकते हैं कि समानांतर धारा एक बार में 8 आइटम बनाती है, अर्थात यह 8 थ्रेड का उपयोग करती है। हालाँकि, यदि मैं टिप्पणी की गई लाइन को अनफिल्ट करता हूँ, तो आउटपुट है:

215 215 215 215 215 216 216 216 216 216 216 216 216 216 216 216 216 216

इस बार, समानांतर धारा में 20 थ्रेड्स का उपयोग किया गया है और स्ट्रीम में सभी 20 तत्वों को समवर्ती रूप से संसाधित किया गया है।


30
commonPoolएक से कम वास्तव में है availableProcessorsके बराबर, कुल समानांतरवाद में जिसके परिणामस्वरूप availableProcessors, क्योंकि एक के रूप में बुला धागा मायने रखता है।
मार्को टोपोलनिक

2
रिटर्न जमा करें ForkJoinTask। नकल करने की parallel() get()जरूरत है:stream.parallel().forEach(soSomething)).get();
ग्रिगोरी किसलिन

5
मैं आश्वस्त नहीं हूं कि ForkJoinPool.submit(() -> stream.forEach(...))दिए गए मेरे स्ट्रीम एक्शन चलेंगे ForkJoinPool। मैं उम्मीद करूंगा कि पूरे स्ट्रीम-एक्शन को ForJoinPool में वन एक्शन के रूप में निष्पादित किया गया है, लेकिन आंतरिक रूप से अभी भी डिफ़ॉल्ट / सामान्य ForkJoinPool का उपयोग कर रहा है। आपने कहां देखा, कि ForkJoinPool.submit () आप जो कहते हैं, वह क्या करेंगे?
फ्रेडरिक लीटनबर्गर

@FredericLeitenberger आप शायद लुकास के जवाब के नीचे अपनी टिप्पणी देने के लिए थे।
17

2
अब मैं देखता हूं कि stackoverflow.com/a/34930831/1520422 अच्छी तरह से दिखाता है कि यह वास्तव में घोषणा के अनुसार काम करता है। फिर भी मैं अभी भी समझ में नहीं आता कि यह कैसे काम करता है। लेकिन मैं "यह काम करता है" के साथ ठीक हूँ। धन्यवाद!
फ्रेडरिक लीटनबर्गर

39

वैकल्पिक रूप से अपने स्वयं के forkJoinPool के अंदर समानांतर गणना को चालू करने की चाल के लिए आप उस पूल को कंप्लीटटेबल Future.supplyAsync विधि में भी पास कर सकते हैं जैसे:

ForkJoinPool forkJoinPool = new ForkJoinPool(2);
CompletableFuture<List<Integer>> primes = CompletableFuture.supplyAsync(() ->
    //parallel task here, for example
    range(1, 1_000_000).parallel().filter(PrimesPrint::isPrime).collect(toList()), 
    forkJoinPool
);

22

मूल समाधान (ForkJoinPool आम समानता संपत्ति सेट करना) अब काम नहीं करता है। मूल उत्तर में लिंक को देखते हुए, एक अद्यतन जो इसे तोड़ता है उसे जावा 8 में वापस पोर्ट किया गया है। जैसा कि लिंक किए गए थ्रेड्स में उल्लेख किया गया है, यह समाधान हमेशा के लिए काम करने की गारंटी नहीं था। उसके आधार पर, समाधान forkjoinpool.submit है। स्वीकृत उत्तर में चर्चा किए गए .get समाधान के साथ। मुझे लगता है कि बैकपोर्ट इस समाधान की अविश्वसनीयता को भी ठीक करता है।

ForkJoinPool fjpool = new ForkJoinPool(10);
System.out.println("stream.parallel");
IntStream range = IntStream.range(0, 20);
fjpool.submit(() -> range.parallel()
        .forEach((int theInt) ->
        {
            try { Thread.sleep(100); } catch (Exception ignore) {}
            System.out.println(Thread.currentThread().getName() + " -- " + theInt);
        })).get();
System.out.println("list.parallelStream");
int [] array = IntStream.range(0, 20).toArray();
List<Integer> list = new ArrayList<>();
for (int theInt: array)
{
    list.add(theInt);
}
fjpool.submit(() -> list.parallelStream()
        .forEach((theInt) ->
        {
            try { Thread.sleep(100); } catch (Exception ignore) {}
            System.out.println(Thread.currentThread().getName() + " -- " + theInt);
        })).get();

जब मैं ForkJoinPool.commonPool().getParallelism()डीबग मोड में करता हूं तो मुझे समानता में परिवर्तन दिखाई नहीं देता है।
d- कोडर

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

मैं इसे क्यों प्राप्त कर रहा हूं: unreported exception InterruptedException; must be caught or declared to be thrownयहां तक catchकि लूप के सभी अपवादों के साथ ।
रॉकी ली

रॉकी, मुझे कोई त्रुटि दिखाई नहीं दे रही है। जावा संस्करण और सटीक लाइन को जानने से मदद मिलेगी। "InterruptedException" का सुझाव है कि नींद के आसपास की कोशिश / पकड़ आपके संस्करण में ठीक से बंद नहीं है।
टॉड कैसेंटेंट

13

हम निम्नलिखित संपत्ति का उपयोग करके डिफ़ॉल्ट समानता को बदल सकते हैं:

-Djava.util.concurrent.ForkJoinPool.common.parallelism=16

जो अधिक समानता का उपयोग करने के लिए सेट कर सकता है।


हालाँकि यह एक वैश्विक सेटिंग है, यह
स्ट्रीम

यह मेरे लिए Openjdk संस्करण "1.8.0_222" पर काम किया
abbas

ऊपर के रूप में एक ही व्यक्ति, यह मेरे लिए काम नहीं कर रहा है Openjdk "11.0.6" पर
abbas

8

उपयोग किए गए थ्रेड्स की वास्तविक संख्या को मापने के लिए, आप देख सकते हैं Thread.activeCount():

    Runnable r = () -> IntStream
            .range(-42, +42)
            .parallel()
            .map(i -> Thread.activeCount())
            .max()
            .ifPresent(System.out::println);

    ForkJoinPool.commonPool().submit(r).join();
    new ForkJoinPool(42).submit(r).join();

यह 4-कोर सीपीयू जैसे आउटपुट पर उत्पादन कर सकता है:

5 // common pool
23 // custom pool

इसके बिना .parallel()देता है:

3 // common pool
4 // custom pool

6
The Thread.activeCount () आपको यह नहीं बताता कि थ्रेड्स आपकी स्ट्रीम को क्या प्रोसेस कर रहे हैं। इसके बजाय Map.currentThread ()। GetName () के लिए मैप करें, इसके बाद एक अलग ()। तब आपको महसूस होगा कि पूल में हर धागे का उपयोग नहीं किया जाएगा ... अपने प्रसंस्करण में देरी जोड़ें और पूल में सभी थ्रेड्स का उपयोग किया जाएगा।
कीऑक्सी

7

अब तक, मैंने इस प्रश्न के उत्तर में वर्णित समाधानों का उपयोग किया। अब, मैं उस के लिए समानांतर स्ट्रीम सपोर्ट नामक एक छोटी सी लाइब्रेरी लेकर आया :

ForkJoinPool pool = new ForkJoinPool(NR_OF_THREADS);
ParallelIntStreamSupport.range(1, 1_000_000, pool)
    .filter(PrimesPrint::isPrime)
    .collect(toList())

लेकिन @PabloMatiasGomez ने टिप्पणियों में बताया, समानांतर धाराओं के विभाजन तंत्र के बारे में कमियां हैं जो सामान्य पूल के आकार पर भारी निर्भर करती हैं। देखें हाशसेट से समानांतर धारा समानांतर में नहीं चलती है

मैं इस समाधान का उपयोग केवल विभिन्न प्रकार के कार्यों के लिए अलग-अलग पूल के लिए कर रहा हूं, लेकिन मैं सामान्य पूल का आकार 1 पर सेट नहीं कर सकता, भले ही मैं इसका उपयोग न करूं।


4

नोट: JDK 10 में एक फिक्स कार्यान्वित प्रतीत होता है जो यह सुनिश्चित करता है कि कस्टम थ्रेड पूल थ्रेड्स की अपेक्षित संख्या का उपयोग करता है।

एक कस्टम ForkJoinPool के भीतर समानांतर धारा का निष्पादन समानता का पालन करना चाहिए https://bugs.openjdk.java.net/browse/JDK-8190974


1

मैंने पूल के आकार को समायोजित करने के लिए कस्टम ForkJoinPool की कोशिश की :

private static Set<String> ThreadNameSet = new HashSet<>();
private static Callable<Long> getSum() {
    List<Long> aList = LongStream.rangeClosed(0, 10_000_000).boxed().collect(Collectors.toList());
    return () -> aList.parallelStream()
            .peek((i) -> {
                String threadName = Thread.currentThread().getName();
                ThreadNameSet.add(threadName);
            })
            .reduce(0L, Long::sum);
}

private static void testForkJoinPool() {
    final int parallelism = 10;

    ForkJoinPool forkJoinPool = null;
    Long result = 0L;
    try {
        forkJoinPool = new ForkJoinPool(parallelism);
        result = forkJoinPool.submit(getSum()).get(); //this makes it an overall blocking call

    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    } finally {
        if (forkJoinPool != null) {
            forkJoinPool.shutdown(); //always remember to shutdown the pool
        }
    }
    out.println(result);
    out.println(ThreadNameSet);
}

यहाँ आउटपुट कह रहा है कि पूल डिफ़ॉल्ट 4 की तुलना में अधिक थ्रेड्स का उपयोग कर रहा है ।

50000005000000
[ForkJoinPool-1-worker-8, ForkJoinPool-1-worker-9, ForkJoinPool-1-worker-6, ForkJoinPool-1-worker-11, ForkJoinPool-1-worker-10, ForkJoinPool-1-worker-1, ForkJoinPool-1-worker-15, ForkJoinPool-1-worker-13, ForkJoinPool-1-worker-4, ForkJoinPool-1-worker-2]

लेकिन वास्तव में एक अजीब बात है , जब मैंने ThreadPoolExecutorनिम्न परिणाम का उपयोग करने की कोशिश की :

BlockingDeque blockingDeque = new LinkedBlockingDeque(1000);
ThreadPoolExecutor fixedSizePool = new ThreadPoolExecutor(10, 20, 60, TimeUnit.SECONDS, blockingDeque, new MyThreadFactory("my-thread"));

लेकिन मैं असफल रहा।

यह केवल एक नए थ्रेड में समानांतर स्ट्रीम शुरू करेगा और फिर बाकी सब कुछ बस एक ही है, जो फिर से साबित करता है कि विल अपने बच्चे के धागे को शुरू करने के लिए ForkJoinPool का parallelStreamउपयोग करेगा ।


अन्य निष्पादकों को अनुमति न देने के पीछे संभावित कारण क्या हो सकता है?
ओमजी

@omjego यह एक अच्छा सवाल है कि शायद आप एक नया सवाल शुरू कर सकते हैं और अपने विचारों को विस्तृत करने के लिए और अधिक विवरण प्रदान कर सकते हैं;)
हार्न

1

AbacusUtil पाने के लिए जाएं । समानांतर स्ट्रीम के लिए निर्दिष्ट थ्रेड नंबर। यहाँ नमूना कोड है:

LongStream.range(4, 1_000_000).parallel(threadNum)...

प्रकटीकरण il मैं AbacusUtil का डेवलपर हूं।


1

यदि आप कार्यान्वयन हैक पर भरोसा नहीं करना चाहते हैं, तो कस्टम कलेक्टरों को लागू करने mapऔर collectसिमेंटिकों को लागू करने के द्वारा हमेशा इसे प्राप्त करने का एक तरीका है ... और आप ForkJoinPool तक सीमित नहीं होंगे:

list.stream()
  .collect(parallelToList(i -> fetchFromDb(i), executor))
  .join()

सौभाग्य से, यह पहले से ही यहाँ किया गया है और मावेन सेंट्रल पर उपलब्ध है: http://github.com/pivovarit/parallel-colorsors

डिस्क्लेमर: मैंने इसे लिखा और इसकी जिम्मेदारी ली।


0

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

 ReactiveSeq.range(1, 1_000_000)
            .foldParallel(new ForkJoinPool(10),
                          s->s.filter(i->true)
                              .peek(i->System.out.println("Thread " + Thread.currentThread().getId()))
                              .max(Comparator.naturalOrder()));

या अगर हम एक अनुक्रमिक स्ट्रीम के भीतर प्रसंस्करण जारी रखना चाहते हैं

 ReactiveSeq.range(1, 1_000_000)
            .parallel(new ForkJoinPool(10),
                      s->s.filter(i->true)
                          .peek(i->System.out.println("Thread " + Thread.currentThread().getId())))
            .map(this::processSequentially)
            .forEach(System.out::println);

[प्रकटीकरण मैं चक्रवात-प्रतिक्रिया का प्रमुख विकासकर्ता हूं]


0

यदि आपको एक कस्टम थ्रेडपूल की आवश्यकता नहीं है, लेकिन आप समवर्ती कार्यों की संख्या को सीमित करना चाहते हैं, तो आप उपयोग कर सकते हैं:

List<Path> paths = List.of("/path/file1.csv", "/path/file2.csv", "/path/file3.csv").stream().map(e -> Paths.get(e)).collect(toList());
List<List<Path>> partitions = Lists.partition(paths, 4); // Guava method

partitions.forEach(group -> group.parallelStream().forEach(csvFilePath -> {
       // do your processing   
}));

(डुप्लीकेट प्रश्न पूछ रहा है कि यह बंद है, इसलिए कृपया मुझे यहां रखें)


-2

आप इस ForkJoinWorkerThreadFactory को लागू करने की कोशिश कर सकते हैं और इसे Fork-Join क्लास में इंजेक्ट कर सकते हैं।

public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode) {
        this(checkParallelism(parallelism),
             checkFactory(factory),
             handler,
             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
             "ForkJoinPool-" + nextPoolId() + "-worker-");
        checkPermission();
    }

ऐसा करने के लिए आप फोर्क-जॉइन पूल के इस कंस्ट्रक्टर का उपयोग कर सकते हैं।

नोट: - 1. यदि आप इसका उपयोग करते हैं, तो ध्यान रखें कि आपके नए थ्रेड्स के कार्यान्वयन के आधार पर, जेवीएम से शेड्यूलिंग प्रभावित होगी, जो आम तौर पर अलग-अलग कोर के लिए थ्रेड-जॉइन थ्रेड्स को शेड्यूल करता है (एक कम्प्यूटेशनल थ्रेड के रूप में माना जाता है)। 2. कांटे में शामिल होने से कार्य शेड्यूलिंग थ्रेड्स प्रभावित नहीं होंगे। 3. वास्तव में यह पता नहीं लगाया गया है कि कांटा-ज्वाइन से समानांतर धारा कैसे थ्रेड उठा रही है (इस पर उचित दस्तावेज नहीं मिल सकता है), इसलिए एक अलग थ्रेडिंग फैक्टरी का उपयोग करने का प्रयास करें ताकि सुनिश्चित हो सके, अगर समानांतर धारा में थ्रेड्स उठाए जा रहे हैं। CustomThreadFactory से जो आप प्रदान करते हैं। 4. commonThreadPool इस customThreadFactory का उपयोग नहीं करेगा।


क्या आप एक प्रयोग करने योग्य उदाहरण प्रदान कर सकते हैं जो यह दर्शाता है कि आपने जो निर्दिष्ट किया है उसका उपयोग कैसे करें?
जे। मुर्रे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.