एक्सेकॉर्स सर्विस जो टाइमआउट के बाद कार्यों को बाधित करती है


93

मैं एक ExecutorService कार्यान्वयन की तलाश कर रहा हूं जिसे टाइमआउट के साथ प्रदान किया जा सकता है। ExecutorService को सबमिट किए जाने वाले कार्य बाधित हो जाते हैं यदि उन्हें चलाने के लिए समय से अधिक समय लगता है। इस तरह के जानवर को लागू करना इतना मुश्किल काम नहीं है, लेकिन अगर कोई मौजूदा कार्यान्वयन के बारे में जानता है तो मैं सोच रहा हूं।

यहाँ नीचे की कुछ चर्चा के आधार पर मैं आया हूँ। कोई टिप्पणी?

import java.util.List;
import java.util.concurrent.*;

public class TimeoutThreadPoolExecutor extends ThreadPoolExecutor {
    private final long timeout;
    private final TimeUnit timeoutUnit;

    private final ScheduledExecutorService timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
    private final ConcurrentMap<Runnable, ScheduledFuture> runningTasks = new ConcurrentHashMap<Runnable, ScheduledFuture>();

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    public TimeoutThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler, long timeout, TimeUnit timeoutUnit) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        this.timeout = timeout;
        this.timeoutUnit = timeoutUnit;
    }

    @Override
    public void shutdown() {
        timeoutExecutor.shutdown();
        super.shutdown();
    }

    @Override
    public List<Runnable> shutdownNow() {
        timeoutExecutor.shutdownNow();
        return super.shutdownNow();
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        if(timeout > 0) {
            final ScheduledFuture<?> scheduled = timeoutExecutor.schedule(new TimeoutTask(t), timeout, timeoutUnit);
            runningTasks.put(r, scheduled);
        }
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        ScheduledFuture timeoutTask = runningTasks.remove(r);
        if(timeoutTask != null) {
            timeoutTask.cancel(false);
        }
    }

    class TimeoutTask implements Runnable {
        private final Thread thread;

        public TimeoutTask(Thread thread) {
            this.thread = thread;
        }

        @Override
        public void run() {
            thread.interrupt();
        }
    }
}

क्या जमा करने के समय का वह 'आरंभ समय' है? या जिस समय कार्य निष्पादित होने लगता है?
टिम बेंडर

अच्छा प्रश्न। जब यह क्रियान्वित होने लगे। संभवतः protected void beforeExecute(Thread t, Runnable r)हुक का उपयोग करना ।
एडवर्ड डेल

@ scompt.com क्या आप अभी भी इस समाधान का उपयोग कर रहे हैं या यह सुपरिचित किया गया है
पॉल टेलर

@PaulTaylor इस समाधान को लागू करने वाली नौकरी को सुपरसीड किया गया है। :-)
एडवर्ड डेल

मुझे इसकी बिल्कुल आवश्यकता है, सिवाय इसके) मुझे अपने मुख्य अनुसूचक सेवा की आवश्यकता है एक एकल सेवा धागा के साथ एक थ्रेड पूल होना चाहिए क्योंकि मेरे कार्यों को कड़ाई से समवर्ती रूप से निष्पादित करने की आवश्यकता है और ख) मुझे प्रत्येक कार्य के लिए समय-अवधि निर्दिष्ट करने में सक्षम होना चाहिए। समय प्रस्तुत किया गया है। मैंने इसे एक शुरुआती बिंदु के रूप में उपयोग करने की कोशिश की है, लेकिन शेड्यूल्डट्रेडपूल एक्सक्यूटोर को विस्तारित करने के लिए, लेकिन मैं टाइमआउट अवधि को निर्दिष्ट करने का एक तरीका नहीं देख सकता हूं जो कि कार्य निष्पादन समय पर निर्दिष्ट किया जाना है। किसी भी सुझाव कृतज्ञता की सराहना की!
माइकल एलिस

जवाबों:


89

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

 ScheduledExecutorService executor = Executors.newScheduledThreadPool(2); 
 final Future handler = executor.submit(new Callable(){ ... });
 executor.schedule(new Runnable(){
     public void run(){
         handler.cancel();
     }      
 }, 10000, TimeUnit.MILLISECONDS);

यह आपके हैंडलर को (10 मिनट के लिए बाधित होने वाली मुख्य कार्यक्षमता) निष्पादित करेगा, फिर उस विशिष्ट कार्य को रद्द कर देगा (यानी बीच में)।


12
दिलचस्प विचार है, लेकिन क्या होगा यदि समय समाप्त होने से पहले कार्य समाप्त हो जाता है (जो सामान्य रूप से होगा)? मैं नहीं बल्कि बहुत सारे सफाई कार्य करने के लिए इंतजार कर रहा था कि केवल अपने निर्धारित कार्य को पूरा करने के लिए दौड़ने की प्रतीक्षा कर रहा है। फ्यूचर्स की निगरानी के लिए एक और धागा होना चाहिए क्योंकि वे अपने सफाई कार्यों को हटाने के लिए समाप्त हो जाते हैं।
एडवर्ड डेल

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

3
यह सच है, लेकिन अगर टाइमआउट 5 घंटे है और उस समय में 10k कार्यों को निष्पादित किया जाता है। मैं उन सभी नो-ऑप्स को लेने से बचना चाहूंगा, जो मेमोरी लेने और संदर्भ स्विच करने के लिए झूठ बोल रहे हैं।
एडवर्ड डेल

1
@ आवश्यक नहीं। 10k future.cancel () इनवोकेशन होंगे, हालांकि अगर भविष्य पूरा हो जाता है, तो कैंसिल तेजी से रास्ता निकाल लेगा और कोई अनहोनी काम नहीं करेगा। यदि आप 10k अतिरिक्त रद्द इनवोकेशन नहीं चाहते हैं, तो यह काम नहीं कर सकता है, लेकिन जब एक कार्य पूरा हो जाता है तो काम की मात्रा बहुत कम होती है।
जॉन विंट

6
@ जॉन डब्ल्यू .: मुझे आपके कार्यान्वयन के साथ एक और मुद्दा महसूस हुआ। मुझे उस समय शुरू करने की आवश्यकता है जब कार्य निष्पादन शुरू होता है, जैसा कि मैंने पहले टिप्पणी की थी। मुझे लगता है कि beforeExecuteहुक का उपयोग करने का एकमात्र तरीका है ।
एडवर्ड डेल

6

दुर्भाग्य से समाधान त्रुटिपूर्ण है। इस प्रश्नScheduledThreadPoolExecutor में रिपोर्ट के साथ एक प्रकार का बग भी है : प्रस्तुत कार्य को रद्द करना कार्य से जुड़े स्मृति संसाधनों को पूरी तरह से जारी नहीं करता है; कार्य समाप्त होने पर ही संसाधन जारी किए जाते हैं।

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

आप निम्न (बहुत क्रूड) परीक्षण कार्यक्रम के साथ समस्या देख सकते हैं:

public static void main(String[] args) throws InterruptedException {
    ExecutorService service = new TimeoutThreadPoolExecutor(1, 1, 10, TimeUnit.SECONDS, 
            new LinkedBlockingQueue<Runnable>(), 10, TimeUnit.MINUTES);
    //ExecutorService service = Executors.newFixedThreadPool(1);
    try {
        final AtomicInteger counter = new AtomicInteger();
        for (long i = 0; i < 10000000; i++) {
            service.submit(new Runnable() {
                @Override
                public void run() {
                    counter.incrementAndGet();
                }
            });
            if (i % 10000 == 0) {
                System.out.println(i + "/" + counter.get());
                while (i > counter.get()) {
                    Thread.sleep(10);
                }
            }
        }
    } finally {
        service.shutdown();
    }
}

कार्यक्रम उपलब्ध मेमोरी को समाप्त कर देता है, हालांकि यह स्पॉन्डेड Runnableएस के पूरा होने का इंतजार करता है ।

हालांकि मैं थोड़ी देर के लिए इस बारे में था, लेकिन दुर्भाग्य से मैं एक अच्छा समाधान नहीं ला सका।

संपादित करें: मुझे पता चला कि इस मुद्दे को JDK बग 6602600 के रूप में रिपोर्ट किया गया था , और प्रतीत होता है कि हाल ही में तय किया गया था।


4

FutureTask में कार्य को लपेटें और आप FutureTask के लिए टाइमआउट निर्दिष्ट कर सकते हैं। इस प्रश्न के मेरे उत्तर में उदाहरण देखें,

जावा देशी प्रक्रिया समय समाप्त


1
मुझे लगता है कि java.util.concurrentवर्गों का उपयोग करने के लिए कुछ तरीके हैं, लेकिन मैं एक ExecutorServiceकार्यान्वयन की तलाश कर रहा हूं ।
एडवर्ड डेल

1
यदि आप कह रहे हैं कि आप चाहते हैं कि आपका एक्सकॉर्स सर्विस इस तथ्य को छुपाये कि क्लाइंट कोड से टाइमआउट जोड़े जा रहे हैं, तो आप अपने एक्सेकॉर्स सर्विस को लागू कर सकते हैं, जो उन्हें चलाने से पहले फ्यूजनटैस्क के साथ प्रत्येक रनरटेबल को लपेटता है।
erikprice

2

सर्वेक्षण करने के लिए टन के बाद,
अंत में, मैं इस समस्या को हल करने invokeAllके ExecutorServiceलिए विधि का उपयोग करता हूं ।
यह कार्य चलने के दौरान कार्य को सख्ती से बाधित करेगा।
यहाँ उदाहरण है

ExecutorService executorService = Executors.newCachedThreadPool();

try {
    List<Callable<Object>> callables = new ArrayList<>();
    // Add your long time task (callable)
    callables.add(new VaryLongTimeTask());
    // Assign tasks for specific execution timeout (e.g. 2 sec)
    List<Future<Object>> futures = executorService.invokeAll(callables, 2000, TimeUnit.MILLISECONDS);
    for (Future<Object> future : futures) {
        // Getting result
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

executorService.shutdown();

समर्थक है आप भी ListenableFutureउसी पर जमा कर सकते हैं ExecutorService
कोड की पहली पंक्ति को थोड़ा बदल दें।

ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

ListeningExecutorServiceExecutorServiceGoogle अमरूद परियोजना ( com.google.guava ) की श्रवण विशेषता )


2
इशारा करने के लिए धन्यवाद invokeAll। यह बहुत अच्छा काम करता है। इसका उपयोग करने के बारे में सोचने वाले किसी के लिए भी सावधानी का एक शब्द: हालांकि वस्तुओं invokeAllकी एक सूची लौटाता है Future, यह वास्तव में एक अवरुद्ध ऑपरेशन लगता है।
एमएक्सआरओ

1

के ExecutorService.shutDownNow()रूप में वर्णित विधि का उपयोग कैसे करेंHttp://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html ? यह सबसे सरल उपाय लगता है।


8
क्योंकि यह सभी निर्धारित कार्यों को रोक देगा और किसी विशिष्ट कार्य को नहीं करेगा जैसा कि प्रश्न द्वारा अनुरोध किया गया था
माइकएल

1

ऐसा लगता है कि समस्या जेडीके बग 6602600 में नहीं है (इसे 2010-05-22 में हल किया गया था), लेकिन सर्कल में नींद (10) की गलत कॉल। अतिरिक्त ध्यान दें, कि मुख्य सूत्र को बाहरी सर्कल की हर शाखा में SLEEP (0) को आमंत्रित करके अन्य कार्यों को समझने के लिए सीधे अन्य धागों को बदलना होगा। यह बेहतर है, मुझे लगता है, थ्रेड के बजाय थ्रेड.लाइड () का उपयोग करने के लिए (0)

पिछली समस्या कोड का सही किया गया परिणाम इस प्रकार है:

.......................
........................
Thread.yield();         

if (i % 1000== 0) {
System.out.println(i + "/" + counter.get()+ "/"+service.toString());
}

//                
//                while (i > counter.get()) {
//                    Thread.sleep(10);
//                } 

यह 150 000 000 परीक्षण किए गए सर्किल तक बाहरी काउंटर की मात्रा के साथ सही ढंग से काम करता है।


1

जॉन डब्ल्यू जवाब का उपयोग करते हुए मैंने एक कार्यान्वयन बनाया जो कार्य को सही तरीके से शुरू करने पर टाइमआउट शुरू करता है। मैं इसके लिए एक इकाई परीक्षण भी लिखता हूँ :)

हालाँकि, यह मेरी आवश्यकताओं के अनुरूप नहीं है क्योंकि कुछ IO संचालन Future.cancel()को कॉल नहीं किया जाता है (जब Thread.interrupt()कहा जाता है)। IO ऑपरेशन के कुछ उदाहरण जो कि Thread.interrupt()कहे जाने पर बाधित नहीं हो सकते हैं Socket.connectऔर Socket.read(और मुझे संदेह है कि अधिकांश IO ऑपरेशन कार्यान्वित हैं java.io)। java.nioजब Thread.interrupt()कहा जाता है सभी IO संचालन में रुकावट होनी चाहिए । उदाहरण के लिए, यह मामला है SocketChannel.openऔर SocketChannel.read

वैसे भी अगर किसी को दिलचस्पी है, तो मैंने एक थ्रेड पूल निष्पादक के लिए एक जिस्ट बनाया जो कार्यों को टाइमआउट करने के लिए अनुमति देता है (यदि वे रुकावट संचालन का उपयोग कर रहे हैं ...): https://gist.github.com/amanteaux/64c54a913c1a34ad7b86db109cbcc0bff


दिलचस्प कोड, मैंने इसे अपने सिस्टम में खींच लिया और जिज्ञासु अगर आपके पास कुछ उदाहरण हैं कि किस तरह के आईओ संचालन बाधित नहीं होंगे तो मैं देख सकता हूं कि क्या यह मेरे सिस्टम को प्रभावित करेगा। धन्यवाद!
डंकन क्रेब्स

@ डंकनके्रब्स ने मेरे उत्तर को गैर-व्यवधान योग्य IO के उदाहरण के साथ विस्तृत किया: Socket.connectऔरSocket.read
एमांटुओ

myThread.interrupted()यह बाधित करने का सही तरीका नहीं है, क्योंकि यह रुकावट का झंडा साफ करता है। myThread.interrupt()इसके बजाय का उपयोग करें , और वह सॉकेट के साथ होना चाहिए
डैनियलकुआड्रा

@DanielCuadra: धन्यवाद, ऐसा लगता है कि मैंने एक टाइपो गलती की है क्योंकि Thread.interrupted()यह एक थ्रेड को बाधित करने में सक्षम नहीं है। हालांकि, संचालन को Thread.interrupt()बाधित नहीं करता है java.io, यह केवल java.nioसंचालन पर काम करता है ।
1948 में amanteaux

मैंने interrupt()कई वर्षों से उपयोग किया है और इसने हमेशा java.io संचालन को बाधित किया है (साथ ही साथ अन्य अवरोधक विधियाँ, जैसे कि थ्रेड स्लीप, जेडडीबी कनेक्शन, अवरोधक ले आदि)। हो सकता है कि आपको
बगिया

0

इस वैकल्पिक विचार के बारे में क्या:

  • दो में दो निष्पादक हैं:
    • एक के लिए :
      • कार्य के टाइमआउट के बारे में परवाह किए बिना, कार्य सबमिट करना
      • भविष्य के परिणाम को जोड़ना और वह समय जब इसे आंतरिक संरचना में समाप्त होना चाहिए
    • एक आंतरिक कार्य को निष्पादित करने के लिए जो आंतरिक संरचना की जांच कर रहा है यदि कुछ कार्य समयबाह्य हैं और यदि उन्हें रद्द करना है।

छोटा सा नमूना यहाँ है:

public class AlternativeExecutorService 
{

private final CopyOnWriteArrayList<ListenableFutureTask> futureQueue       = new CopyOnWriteArrayList();
private final ScheduledThreadPoolExecutor                scheduledExecutor = new ScheduledThreadPoolExecutor(1); // used for internal cleaning job
private final ListeningExecutorService                   threadExecutor    = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(5)); // used for
private ScheduledFuture scheduledFuture;
private static final long INTERNAL_JOB_CLEANUP_FREQUENCY = 1000L;

public AlternativeExecutorService()
{
    scheduledFuture = scheduledExecutor.scheduleAtFixedRate(new TimeoutManagerJob(), 0, INTERNAL_JOB_CLEANUP_FREQUENCY, TimeUnit.MILLISECONDS);
}

public void pushTask(OwnTask task)
{
    ListenableFuture<Void> future = threadExecutor.submit(task);  // -> create your Callable
    futureQueue.add(new ListenableFutureTask(future, task, getCurrentMillisecondsTime())); // -> store the time when the task should end
}

public void shutdownInternalScheduledExecutor()
{
    scheduledFuture.cancel(true);
    scheduledExecutor.shutdownNow();
}

long getCurrentMillisecondsTime()
{
    return Calendar.getInstance().get(Calendar.MILLISECOND);
}

class ListenableFutureTask
{
    private final ListenableFuture<Void> future;
    private final OwnTask                task;
    private final long                   milliSecEndTime;

    private ListenableFutureTask(ListenableFuture<Void> future, OwnTask task, long milliSecStartTime)
    {
        this.future = future;
        this.task = task;
        this.milliSecEndTime = milliSecStartTime + task.getTimeUnit().convert(task.getTimeoutDuration(), TimeUnit.MILLISECONDS);
    }

    ListenableFuture<Void> getFuture()
    {
        return future;
    }

    OwnTask getTask()
    {
        return task;
    }

    long getMilliSecEndTime()
    {
        return milliSecEndTime;
    }
}

class TimeoutManagerJob implements Runnable
{
    CopyOnWriteArrayList<ListenableFutureTask> getCopyOnWriteArrayList()
    {
        return futureQueue;
    }

    @Override
    public void run()
    {
        long currentMileSecValue = getCurrentMillisecondsTime();
        for (ListenableFutureTask futureTask : futureQueue)
        {
            consumeFuture(futureTask, currentMileSecValue);
        }
    }

    private void consumeFuture(ListenableFutureTask futureTask, long currentMileSecValue)
    {
        ListenableFuture<Void> future = futureTask.getFuture();
        boolean isTimeout = futureTask.getMilliSecEndTime() >= currentMileSecValue;
        if (isTimeout)
        {
            if (!future.isDone())
            {
                future.cancel(true);
            }
            futureQueue.remove(futureTask);
        }
    }
}

class OwnTask implements Callable<Void>
{
    private long     timeoutDuration;
    private TimeUnit timeUnit;

    OwnTask(long timeoutDuration, TimeUnit timeUnit)
    {
        this.timeoutDuration = timeoutDuration;
        this.timeUnit = timeUnit;
    }

    @Override
    public Void call() throws Exception
    {
        // do logic
        return null;
    }

    public long getTimeoutDuration()
    {
        return timeoutDuration;
    }

    public TimeUnit getTimeUnit()
    {
        return timeUnit;
    }
}
}

0

जांचें कि क्या यह आपके लिए काम करता है,

    public <T,S,K,V> ResponseObject<Collection<ResponseObject<T>>> runOnScheduler(ThreadPoolExecutor threadPoolExecutor,
      int parallelismLevel, TimeUnit timeUnit, int timeToCompleteEachTask, Collection<S> collection,
      Map<K,V> context, Task<T,S,K,V> someTask){
    if(threadPoolExecutor==null){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("threadPoolExecutor can not be null").build();
    }
    if(someTask==null){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("Task can not be null").build();
    }
    if(CollectionUtils.isEmpty(collection)){
      return ResponseObject.<Collection<ResponseObject<T>>>builder().errorCode("500").errorMessage("input collection can not be empty").build();
    }

    LinkedBlockingQueue<Callable<T>> callableLinkedBlockingQueue = new LinkedBlockingQueue<>(collection.size());
    collection.forEach(value -> {
      callableLinkedBlockingQueue.offer(()->someTask.perform(value,context)); //pass some values in callable. which can be anything.
    });
    LinkedBlockingQueue<Future<T>> futures = new LinkedBlockingQueue<>();

    int count = 0;

    while(count<parallelismLevel && count < callableLinkedBlockingQueue.size()){
      Future<T> f = threadPoolExecutor.submit(callableLinkedBlockingQueue.poll());
      futures.offer(f);
      count++;
    }

    Collection<ResponseObject<T>> responseCollection = new ArrayList<>();

    while(futures.size()>0){
      Future<T> future = futures.poll();
      ResponseObject<T> responseObject = null;
        try {
          T response = future.get(timeToCompleteEachTask, timeUnit);
          responseObject = ResponseObject.<T>builder().data(response).build();
        } catch (InterruptedException e) {
          future.cancel(true);
        } catch (ExecutionException e) {
          future.cancel(true);
        } catch (TimeoutException e) {
          future.cancel(true);
        } finally {
          if (Objects.nonNull(responseObject)) {
            responseCollection.add(responseObject);
          }
          futures.remove(future);//remove this
          Callable<T> callable = getRemainingCallables(callableLinkedBlockingQueue);
          if(null!=callable){
            Future<T> f = threadPoolExecutor.submit(callable);
            futures.add(f);
          }
        }

    }
    return ResponseObject.<Collection<ResponseObject<T>>>builder().data(responseCollection).build();
  }

  private <T> Callable<T> getRemainingCallables(LinkedBlockingQueue<Callable<T>> callableLinkedBlockingQueue){
    if(callableLinkedBlockingQueue.size()>0){
      return callableLinkedBlockingQueue.poll();
    }
    return null;
  }

आप शेड्यूलर से थ्रेड के उपयोग की संख्या को प्रतिबंधित कर सकते हैं और साथ ही कार्य पर टाइमआउट कर सकते हैं।

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