किसी थ्रेड को टाइमआउट कैसे करें


255

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

यह करने का एक तरीका जैसा कि मैंने इस धागे से पता लगाया है कि थ्रेड के रन () विधि के अंदर एक टाइमररस्क का उपयोग करना है।

क्या इसके लिए कोई बेहतर उपाय हैं?

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

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


संपादित करें: जैसा कि मुझे अधिक स्पष्ट उत्तर की आवश्यकता थी, एक इनाम जोड़ना। नीचे दिए गए ExecutorService कोड मेरी समस्या का समाधान नहीं करता है। मुझे अपना कोड निष्पादित करने के बाद क्यों सोना चाहिए ()? यदि कोड पूरा हो गया है और नींद () बाधित है, तो यह कैसे हो सकता है?
java_geek

7
यह sleep()"लंबे समय तक चलने वाले कार्य" का प्रतिनिधित्व करने के लिए सिर्फ एक स्टब था। बस इसे अपने वास्तविक कार्य के साथ बदल दें;)
बाल्स्क

1
... एक "लंबे समय तक चलने वाला कार्य" जो interrupt()उसके धागे पर कॉल का जवाब देने के लिए होता है ... सभी "अवरुद्ध" कॉल नहीं करते हैं, जैसा कि मैंने अपने उत्तर में इंगित करने की कोशिश की। जिस कार्य को आप करने की कोशिश कर रहे हैं, उसकी बारीकियों का उपयोग किए जाने वाले दृष्टिकोण में एक बड़ा अंतर है। कार्य के बारे में अधिक जानकारी सहायक होगी।
एरिक्सन

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

ये सूत्र जो आप समय-सीमा तक चाहते हैं; क्या वे अवरुद्ध कॉल कर रहे हैं, या वे कुछ लूप में हैं जहां आप आसानी से कुछ चर देख सकते हैं कि क्या यह छोड़ने का समय है?
स्कॉट स्मिथ

जवाबों:


376

वास्तव में इसके ExecutorServiceबजाय Timer, यहाँ SSCCE का उपयोग करें :

package com.stackoverflow.q2275443;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            future.cancel(true);
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
        return "Ready!";
    }
}

विधि timeoutमें तर्क के साथ थोड़ा खेलें Future#get(), जैसे इसे 5 तक बढ़ाएं और आप देखेंगे कि धागा खत्म हो गया है। आप catch (TimeoutException e)ब्लॉक में मध्यांतर को रोक सकते हैं ।

अद्यतन: एक वैचारिक गलतफहमी स्पष्ट करने के लिए, sleep()है नहीं की आवश्यकता है। यह सिर्फ SSCCE / प्रदर्शन उद्देश्यों के लिए उपयोग किया जाता है। बस अपने लंबे समय से चल रहे कार्य को वहीं करें sleep()। अपने लंबे समय तक चलने वाले कार्य के अंदर, आपको जाँच करनी चाहिए कि क्या धागा बाधित नहीं हुआ है निम्नानुसार है:

while (!Thread.interrupted()) {
    // Do your long running task here.
}

24
Thread.sleep(4000)कुछ अन्य लंबे समय से चल रहे बयान के साथ बदलें और उदाहरण काम नहीं करेगा। दूसरे शब्दों में, यह उदाहरण केवल तभी काम करेगा जब स्थिति परिवर्तन Taskको समझने के लिए डिज़ाइन किया गया हो Thread.isInterrupted()
yegor256

@ बाल्सक मैंने अपने थ्रेड को समाप्त करने के लिए इस दृष्टिकोण की कोशिश की, लेकिन यह काम नहीं कर सका। आप इसे यहाँ देख सकते हैं: stackoverflow.com/questions/35553420/…
syfantid

InterruptedException को भविष्य में कैसे बनाया जाता है।
बोलेई

1
n लोगों की संख्या ने पैकेज के नाम के बारे में टिप्पणी की है, और यहां इसके लिए एक और +1 है। यह इतना अच्छा कौशल है कि इसे आत्मसात किया जाए। धन्यवाद!
अश्विन तुममा

@ बालसुख मुझे संदेह है, कि क्या भविष्य समकालिक रूप से निष्पादित होगा और यदि यह पूर्वनिर्धारित समय से अधिक समय लेता है तो इसे समाप्त कर दिया जाएगा। इसके अलावा यह भविष्य में कुछ समय के दौरान निष्पादित करेगा, इस बीच हम समय पर गिन रहे हैं ... धन्यवाद
आदिल अहमद

49

किसी भी पुराने कार्य के लिए ऐसा करने का 100% विश्वसनीय तरीका नहीं है। कार्य को इस क्षमता को ध्यान में रखकर लिखा जाना चाहिए।

कोर जावा लाइब्रेरियों जैसे कार्यकर्ता सूत्र पर कॉल के ExecutorServiceसाथ अतुल्यकालिक कार्यों को रद्द interrupt()करते हैं। इसलिए, उदाहरण के लिए, यदि कार्य में कुछ प्रकार के लूप शामिल हैं, तो आपको प्रत्येक पुनरावृत्ति पर इसकी रुकावट की स्थिति की जांच करनी चाहिए । यदि कार्य I / O संचालन कर रहा है, तो उन्हें रुकावट भी होना चाहिए - और यह निर्धारित करना कि मुश्किल हो सकता है। किसी भी मामले में, ध्यान रखें कि कोड को सक्रिय रूप से इंटरप्ट के लिए जांचना है; एक रुकावट सेट करना जरूरी नहीं है।

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


मेरे अनुभव में बाधित करने के लिए प्रतिक्रिया नहीं करने वाला एकमात्र कोड देशी कोड (ऑपरेटिंग सिस्टम की प्रतीक्षा) में अवरुद्ध है।
थोरबजोरन रेव एंडरसन

@ ThorbjørnRavnAndersen मैं सहमत हूं, लेकिन यह बहुत कोड है। मेरा कहना है कि इसके लिए कोई सामान्य-प्रयोजन तंत्र नहीं है; आपको कार्य की रुकावट नीति को समझना होगा।
इरिकसन

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

कैंट एग्ज़ॉर्म्स सर्विस कॉलिंग थ्रेड पर कार्य चलाने का विकल्प चुनती है? भविष्य में किसी समय कार्य निष्पादित करने का विकल्प भी निष्पादित कर सकता है?
गंदी_विलास

@ user1232726 execute()अभिभावक इंटरफ़ेस की विधि, Executorकॉलिंग थ्रेड में एक कार्य चला सकती है। उस वापसी उदाहरण के submit()तरीकों के लिए कोई समान कथन नहीं है । सेवा का निहितार्थ यह है कि श्रमिक सूत्र हैं जिन्हें शटडाउन के माध्यम से साफ किया जाना है, और उन कार्यों को अतुल्यकालिक रूप से निष्पादित किया जाता है। उस ने कहा, अनुबंध में ऐसा कुछ भी नहीं है जो कहता है कि सबमिट थ्रेड में कार्यों को निष्पादित करने से निषिद्ध है; वे गारंटी फैक्ट्रियों की तरह कार्यान्वयन एपीआई से आते हैं । ExecutorServiceFutureExecutorServiceExecutors
इरिकसन

13

ExecutorService की एक आवृत्ति का उपयोग करने पर विचार करें । दोनों invokeAll()और invokeAny()विधियां एक के साथ उपलब्ध हैंtimeout पैरामीटर के ।

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


9

मान लें कि थ्रेड कोड आपके नियंत्रण से बाहर है:

ऊपर उल्लिखित जावा प्रलेखन से:

क्या होगा यदि कोई धागा Thread.interrupt का जवाब नहीं देता है?

कुछ मामलों में, आप एप्लिकेशन विशिष्ट ट्रिक्स का उपयोग कर सकते हैं। उदाहरण के लिए, यदि कोई थ्रेड सॉकेट पर प्रतीक्षा कर रहा है, तो आप सॉकेट को बंद कर सकते हैं जिससे थ्रेड तुरंत वापस आ सके। दुर्भाग्य से, वास्तव में कोई भी तकनीक नहीं है जो सामान्य रूप से काम करती है। यह ध्यान दिया जाना चाहिए कि सभी स्थितियों में जहां एक थ्रेड थ्रेड थ्रेड.इंटरप्ट पर प्रतिक्रिया नहीं करता है, यह थ्रेड.स्टॉप पर भी प्रतिक्रिया नहीं करेगा। इस तरह के मामलों में जानबूझकर इनकार करने वाली सेवा के हमले शामिल हैं, और I / O संचालन जिसके लिए थ्रेड.स्टॉप और थ्रेड.इन्टरप्ट ठीक से काम नहीं करते हैं।

जमीनी स्तर:

सुनिश्चित करें कि सभी थ्रेड्स को बाधित किया जा सकता है, या फिर आपको थ्रेड के विशिष्ट ज्ञान की आवश्यकता है - जैसे कि एक ध्वज सेट करने के लिए। हो सकता है कि आप इसे रोकने के लिए आवश्यक कोड के साथ कार्य को दे सकते हैं - एक stop()विधि के साथ एक इंटरफ़ेस परिभाषित करें । जब आप किसी कार्य को रोकने में विफल रहे तो आपको चेतावनी भी दे सकते हैं।


8

BalusC ने कहा:

अपडेट: एक वैचारिक गलतफहमी को स्पष्ट करने के लिए, नींद () की आवश्यकता नहीं है। यह सिर्फ SSCCE / प्रदर्शन उद्देश्यों के लिए उपयोग किया जाता है। बस सोने के स्थान पर अपने लंबे चलने वाले कार्य को वहीं करें ()।

लेकिन अगर आप के Thread.sleep(4000);साथ प्रतिस्थापित करते हैं for (int i = 0; i < 5E8; i++) {}तो यह संकलित नहीं करता है, क्योंकि खाली लूप ए नहीं फेंकता है InterruptedException

और थ्रेड के लिए रुकावट के लिए, इसे फेंकने की आवश्यकता है InterruptedException

यह मुझे एक गंभीर समस्या लगती है। मैं यह नहीं देख सकता कि सामान्य लंबे समय तक चलने वाले कार्य के साथ इस उत्तर को कैसे अनुकूलित किया जाए।

जोड़ने के लिए संपादित: मैंने इसे एक नए प्रश्न के रूप में फिर से लिखा: [ तय समय के बाद एक थ्रेड को बाधित करना, क्या इसमें इंटरप्टेड एक्ससेप्शन फेंकना है? ]


जिस तरह से मैं यह कर रहा हूँ कि पब्लिक क्लास में एक ´थ्रोस अपवाद को जोड़ना है <T> कॉल {} विधि
रॉबर्टो लिनारेस

5

मुझे लगता है कि आपको उचित संगामिति तंत्र पर एक नज़र डालनी चाहिए (अनंत छोरों में चलने वाले धागे प्रति सीड, बीडब्ल्यूटी अच्छा नहीं लगता है)। सुनिश्चित करें कि आपने थ्रेड्स विषय को "मार" या "रोक" के बारे में थोड़ा पढ़ा है ।

आप जो वर्णन कर रहे हैं, वह एक " गायन-योग्य " की तरह ध्वनि करता है, इसलिए आप चक्रीय बैरियर पर एक नज़र डालना चाहते हैं

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

मैं आमतौर पर इस क्षेत्र में दो पुस्तकों की सलाह देता हूं: जावा में संकलित प्रोग्रामिंग और व्यवहार में जावा कंजेरिबिलिटी


5

मैंने कुछ समय पहले ही इसके लिए एक सहायक वर्ग बनाया था। बहुत अच्छा काम करता है:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * TimeOut class - used for stopping a thread that is taking too long
 * @author Peter Goransson
 *
 */
public class TimeOut {

    Thread interrupter;
    Thread target;
    long timeout;
    boolean success;
    boolean forceStop;

    CyclicBarrier barrier;

    /**
     * 
     * @param target The Runnable target to be executed
     * @param timeout The time in milliseconds before target will be interrupted or stopped
     * @param forceStop If true, will Thread.stop() this target instead of just interrupt() 
     */
    public TimeOut(Runnable target, long timeout, boolean forceStop) {      
        this.timeout = timeout;
        this.forceStop = forceStop;

        this.target = new Thread(target);       
        this.interrupter = new Thread(new Interrupter());

        barrier = new CyclicBarrier(2); // There will always be just 2 threads waiting on this barrier
    }

    public boolean execute() throws InterruptedException {  

        // Start target and interrupter
        target.start();
        interrupter.start();

        // Wait for target to finish or be interrupted by interrupter
        target.join();  

        interrupter.interrupt(); // stop the interrupter    
        try {
            barrier.await(); // Need to wait on this barrier to make sure status is set
        } catch (BrokenBarrierException e) {
            // Something horrible happened, assume we failed
            success = false;
        } 

        return success; // status is set in the Interrupter inner class
    }

    private class Interrupter implements Runnable {

        Interrupter() {}

        public void run() {
            try {
                Thread.sleep(timeout); // Wait for timeout period and then kill this target
                if (forceStop) {
                  target.stop(); // Need to use stop instead of interrupt since we're trying to kill this thread
                }
                else {
                    target.interrupt(); // Gracefully interrupt the waiting thread
                }
                System.out.println("done");             
                success = false;
            } catch (InterruptedException e) {
                success = true;
            }


            try {
                barrier.await(); // Need to wait on this barrier
            } catch (InterruptedException e) {
                // If the Child and Interrupter finish at the exact same millisecond we'll get here
                // In this weird case assume it failed
                success = false;                
            } 
            catch (BrokenBarrierException e) {
                // Something horrible happened, assume we failed
                success = false;
            }

        }

    }
}

इसे इस तरह कहा जाता है:

long timeout = 10000; // number of milliseconds before timeout
TimeOut t = new TimeOut(new PhotoProcessor(filePath, params), timeout, true);
try {                       
  boolean sucess = t.execute(); // Will return false if this times out
  if (!sucess) {
    // This thread timed out
  }
  else {
    // This thread ran completely and did not timeout
  }
} catch (InterruptedException e) {}  

3

मैं आपको कोड का एक टुकड़ा पोस्ट करता हूं जो समस्या को हल करने का तरीका दिखाता है। उदाहरण के तौर पर मैं एक फाइल पढ़ रहा हूं। आप इस विधि का उपयोग दूसरे ऑपरेशन के लिए कर सकते हैं, लेकिन आपको किल () विधि को लागू करना होगा ताकि मुख्य ऑपरेशन बाधित हो जाए।

आशा करता हूँ की ये काम करेगा


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Main class
 * 
 * @author el
 * 
 */
public class Main {
    /**
     * Thread which perform the task which should be timed out.
     * 
     * @author el
     * 
     */
    public static class MainThread extends Thread {
        /**
         * For example reading a file. File to read.
         */
        final private File fileToRead;
        /**
         * InputStream from the file.
         */
        final private InputStream myInputStream;
        /**
         * Thread for timeout.
         */
        final private TimeOutThread timeOutThread;

        /**
         * true if the thread has not ended.
         */
        boolean isRunning = true;

        /**
         * true if all tasks where done.
         */
        boolean everythingDone = false;

        /**
         * if every thing could not be done, an {@link Exception} may have
         * Happens.
         */
        Throwable endedWithException = null;

        /**
         * Constructor.
         * 
         * @param file
         * @throws FileNotFoundException
         */
        MainThread(File file) throws FileNotFoundException {
            setDaemon(false);
            fileToRead = file;
            // open the file stream.
            myInputStream = new FileInputStream(fileToRead);
            // Instantiate the timeout thread.
            timeOutThread = new TimeOutThread(10000, this);
        }

        /**
         * Used by the {@link TimeOutThread}.
         */
        public void kill() {
            if (isRunning) {
                isRunning = false;
                if (myInputStream != null) {
                    try {
                        // close the stream, it may be the problem.
                        myInputStream.close();
                    } catch (IOException e) {
                        // Not interesting
                        System.out.println(e.toString());
                    }
                }
                synchronized (this) {
                    notify();
                }
            }
        }

        /**
         * The task which should be timed out.
         */
        @Override
        public void run() {
            timeOutThread.start();
            int bytes = 0;
            try {
                // do something
                while (myInputStream.read() >= 0) {
                    // may block the thread.
                    myInputStream.read();
                    bytes++;
                    // simulate a slow stream.
                    synchronized (this) {
                        wait(10);
                    }
                }
                everythingDone = true;
            } catch (IOException e) {
                endedWithException = e;
            } catch (InterruptedException e) {
                endedWithException = e;
            } finally {
                timeOutThread.kill();
                System.out.println("-->read " + bytes + " bytes.");
                isRunning = false;
                synchronized (this) {
                    notifyAll();
                }
            }
        }
    }

    /**
     * Timeout Thread. Kill the main task if necessary.
     * 
     * @author el
     * 
     */
    public static class TimeOutThread extends Thread {
        final long timeout;
        final MainThread controlledObj;

        TimeOutThread(long timeout, MainThread controlledObj) {
            setDaemon(true);
            this.timeout = timeout;
            this.controlledObj = controlledObj;
        }

        boolean isRunning = true;

        /**
         * If we done need the {@link TimeOutThread} thread, we may kill it.
         */
        public void kill() {
            isRunning = false;
            synchronized (this) {
                notify();
            }
        }

        /**
         * 
         */
        @Override
        public void run() {
            long deltaT = 0l;
            try {
                long start = System.currentTimeMillis();
                while (isRunning && deltaT < timeout) {
                    synchronized (this) {
                        wait(Math.max(100, timeout - deltaT));
                    }
                    deltaT = System.currentTimeMillis() - start;
                }
            } catch (InterruptedException e) {
                // If the thread is interrupted,
                // you may not want to kill the main thread,
                // but probably yes.
            } finally {
                isRunning = false;
            }
            controlledObj.kill();
        }
    }

    /**
     * Start the main task and wait for the end.
     * 
     * @param args
     * @throws FileNotFoundException
     */
    public static void main(String[] args) throws FileNotFoundException {
        long start = System.currentTimeMillis();
        MainThread main = new MainThread(new File(args[0]));
        main.start();
        try {
            while (main.isRunning) {
                synchronized (main) {
                    main.wait(1000);
                }
            }
            long stop = System.currentTimeMillis();

            if (main.everythingDone)
                System.out.println("all done in " + (stop - start) + " ms.");
            else {
                System.out.println("could not do everything in "
                        + (stop - start) + " ms.");
                if (main.endedWithException != null)
                    main.endedWithException.printStackTrace();
            }
        } catch (InterruptedException e) {
            System.out.println("You've killed me!");
        }
    }
}

सादर


3

जावा कोड के टुकड़े को चलाने या कॉल करने के लिए हेल्पर क्लास का उपयोग करना यहाँ मेरा बहुत आसान है :-)

इस उत्कृष्ट पर आधारित है जवाब से BalusC

package com.mycompany.util.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Calling {@link Callable#call()} or Running {@link Runnable#run()} code
 * with a timeout based on {@link Future#get(long, TimeUnit))}
 * @author pascaldalfarra
 *
 */
public class CallableHelper
{

    private CallableHelper()
    {
    }

    public static final void run(final Runnable runnable, int timeoutInSeconds)
    {
        run(runnable, null, timeoutInSeconds);
    }

    public static final void run(final Runnable runnable, Runnable timeoutCallback, int timeoutInSeconds)
    {
        call(new Callable<Void>()
        {
            @Override
            public Void call() throws Exception
            {
                runnable.run();
                return null;
            }
        }, timeoutCallback, timeoutInSeconds); 
    }

    public static final <T> T call(final Callable<T> callable, int timeoutInSeconds)
    {
        return call(callable, null, timeoutInSeconds); 
    }

    public static final <T> T call(final Callable<T> callable, Runnable timeoutCallback, int timeoutInSeconds)
    {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        try
        {
            Future<T> future = executor.submit(callable);
            T result = future.get(timeoutInSeconds, TimeUnit.SECONDS);
            System.out.println("CallableHelper - Finished!");
            return result;
        }
        catch (TimeoutException e)
        {
            System.out.println("CallableHelper - TimeoutException!");
            if(timeoutCallback != null)
            {
                timeoutCallback.run();
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }
        finally
        {
            executor.shutdownNow();
            executor = null;
        }

        return null;
    }

}

2

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

ExecutorService executorService = getExecutorService();
Future<SomeClass> future = executorService.submit(new Callable<SomeClass>() {
    public SomeClass call() {
        // Perform long-running task, return result. The code should check
        // interrupt status regularly, to facilitate cancellation.
    }
});
try {
    // Real life code should define the timeout as a constant or
    // retrieve it from configuration
    SomeClass result = future.get(10, TimeUnit.SECONDS);
    // Do something with the result
} catch (TimeoutException e) {
    future.cancel(true);
    // Perform other error handling, e.g. logging, throwing an exception
}

getExecutorService()विधि तरीके का एक संख्या में लागू किया जा सकता है। यदि आपके पास कोई विशेष आवश्यकता नहीं है, तो आप बस Executors.newCachedThreadPool()थ्रेड की संख्या पर कोई ऊपरी सीमा के साथ थ्रेड पूलिंग के लिए कॉल कर सकते हैं ।


आयातों की क्या आवश्यकता है? क्या हैं SomeClassऔर Future?
ADTC

2

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

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


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

@AlessandroS: यह एक उचित बिंदु है, हालांकि ओपी ने "बेहतर समाधान" के लिए कहा, जिसके द्वारा मैंने यह मतलब निकाला कि मजबूती और विश्वसनीयता को क्रूर बल पर पसंद किया गया था।
डैन पूजे

2

BalusC का शानदार जवाब:

लेकिन बस यह जोड़ने के लिए कि टाइमआउट स्वयं थ्रेड को बाधित नहीं करता है। यहां तक ​​कि अगर आप अपने कार्य में (! थ्रेड। बाधित) () के साथ जाँच कर रहे हैं। यदि आप यह सुनिश्चित करना चाहते हैं कि थ्रेड बंद कर दिया जाए तो आपको भविष्य में भी सुनिश्चित करना चाहिए। जब ​​टाइमआउट अपवाद पकड़ा जाता है, तो उसे रद्द कर दिया जाता है।

package com.stackoverflow.q2275443; 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


public class Test { 
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try { 
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            //Without the below cancel the thread will continue to live 
            // even though the timeout exception thrown.
            future.cancel();
            System.out.println("Terminated!");
        } 

        executor.shutdownNow();
    } 
} 

class Task implements Callable<String> {
    @Override 
    public String call() throws Exception {
      while(!Thread.currentThread.isInterrupted()){
          System.out.println("Im still running baby!!");
      }          
    } 
} 

0

मुझे लगता है कि उत्तर मुख्य रूप से कार्य पर ही निर्भर करता है।

  • क्या यह एक काम को बार-बार कर रहा है?
  • क्या यह आवश्यक है कि समय समाप्त होने के तुरंत बाद यह वर्तमान में चल रहे कार्य को बाधित कर दे?

यदि पहला उत्तर हाँ है और दूसरा नहीं है, तो आप इसे इस प्रकार सरल रख सकते हैं:

public class Main {

    private static final class TimeoutTask extends Thread {
        private final long _timeoutMs;
        private Runnable _runnable;

        private TimeoutTask(long timeoutMs, Runnable runnable) {
            _timeoutMs = timeoutMs;
            _runnable = runnable;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() < (start + _timeoutMs)) {
                _runnable.run();
            }
            System.out.println("execution took " + (System.currentTimeMillis() - start) +" ms");
        }

    }

    public static void main(String[] args) throws Exception {
        new TimeoutTask(2000L, new Runnable() {

            @Override
            public void run() {
                System.out.println("doing something ...");
                try {
                    // pretend it's taking somewhat longer than it really does
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}

यदि यह कोई विकल्प नहीं है, तो कृपया अपनी आवश्यकताओं को सीमित करें - या कुछ कोड दिखाएं।


0

मैं एक एक्सेकॉर्स सर्विस की तलाश कर रहा था जो इसके द्वारा निष्पादित सभी रन-आउट को बाधित कर सकती है, लेकिन कोई भी नहीं मिला। कुछ घंटों के बाद मैंने नीचे के रूप में एक बनाया। इस वर्ग को मजबूती बढ़ाने के लिए संशोधित किया जा सकता है।

public class TimedExecutorService extends ThreadPoolExecutor {
    long timeout;
    public TimedExecutorService(int numThreads, long timeout, TimeUnit unit) {
        super(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(numThreads + 1));
        this.timeout = unit.toMillis(timeout);
    }

    @Override
    protected void beforeExecute(Thread thread, Runnable runnable) {
        Thread interruptionThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // Wait until timeout and interrupt this thread
                    Thread.sleep(timeout);
                    System.out.println("The runnable times out.");
                    thread.interrupt();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        interruptionThread.start();
    }
}

उपयोग:

public static void main(String[] args) {

    Runnable abcdRunnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("abcdRunnable started");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                // logger.info("The runnable times out.");
            }
            System.out.println("abcdRunnable ended");
        }
    };

    Runnable xyzwRunnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("xyzwRunnable started");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                // logger.info("The runnable times out.");
            }
            System.out.println("xyzwRunnable ended");
        }
    };

    int numThreads = 2, timeout = 5;
    ExecutorService timedExecutor = new TimedExecutorService(numThreads, timeout, TimeUnit.SECONDS);
    timedExecutor.execute(abcdRunnable);
    timedExecutor.execute(xyzwRunnable);
    timedExecutor.shutdown();
}

0

अब, एल इस तरह एक मुद्दे को पूरा करते हैं। यह चित्र को डिकोड करने के लिए होता है। डिकोड की प्रक्रिया में बहुत अधिक समय लगता है कि स्क्रीन काली रहती है। l एक टाइम कंट्रोलर जोड़ें: जब समय बहुत लंबा हो जाए, तो वर्तमान थ्रेड से पॉप अप करें। निम्नलिखित है:

   ExecutorService executor = Executors.newSingleThreadExecutor();
   Future<Bitmap> future = executor.submit(new Callable<Bitmap>() {
       @Override
       public Bitmap call() throws Exception {
       Bitmap bitmap = decodeAndScaleBitmapFromStream(context, inputUri);// do some time consuming operation
       return null;
            }
       });
       try {
           Bitmap result = future.get(1, TimeUnit.SECONDS);
       } catch (TimeoutException e){
           future.cancel(true);
       }
       executor.shutdown();
       return (bitmap!= null);

0

मुझे भी यही समस्या थी। तो मैं इस तरह एक सरल समाधान के साथ आया था।

public class TimeoutBlock {

 private final long timeoutMilliSeconds;
    private long timeoutInteval=100;

    public TimeoutBlock(long timeoutMilliSeconds){
        this.timeoutMilliSeconds=timeoutMilliSeconds;
    }

    public void addBlock(Runnable runnable) throws Throwable{
        long collectIntervals=0;
        Thread timeoutWorker=new Thread(runnable);
        timeoutWorker.start();
        do{ 
            if(collectIntervals>=this.timeoutMilliSeconds){
                timeoutWorker.stop();
                throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
            }
            collectIntervals+=timeoutInteval;           
            Thread.sleep(timeoutInteval);

        }while(timeoutWorker.isAlive());
        System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
    }

    /**
     * @return the timeoutInteval
     */
    public long getTimeoutInteval() {
        return timeoutInteval;
    }

    /**
     * @param timeoutInteval the timeoutInteval to set
     */
    public void setTimeoutInteval(long timeoutInteval) {
        this.timeoutInteval = timeoutInteval;
    }
}

गारंटी देता है कि यदि समय सीमा के भीतर ब्लॉक निष्पादित नहीं हुआ। प्रक्रिया समाप्त हो जाएगी और एक अपवाद फेंकता है।

उदाहरण :

try {
        TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
        Runnable block=new Runnable() {

            @Override
            public void run() {
                //TO DO write block of code 
            }
        };

        timeoutBlock.addBlock(block);// execute the runnable block 

    } catch (Throwable e) {
        //catch the exception here . Which is block didn't execute within the time limit
    }

0

BalusC द्वारा दिए गए समाधान में , मुख्य धागा टाइमआउट अवधि के लिए अवरुद्ध रहेगा। यदि आपके पास एक से अधिक थ्रेड वाला थ्रेड पूल है, तो आपको उतने ही अतिरिक्त थ्रेड की आवश्यकता होगी जो Future.get (लॉन्ग टाइमआउट, TimeUnit यूनिट) का उपयोग कर रहे हों और यदि यह टाइमआउट अवधि से अधिक हो तो थ्रेड को बंद करने के लिए कॉल ब्लॉक करना होगा।

इस समस्या का एक सामान्य समाधान थ्रेडपूल एक्ज़ीक्यूटर डेकोरेटर बनाना है जो टाइमआउट कार्यक्षमता को जोड़ सकता है। इस सज्जाकार वर्ग को थ्रेडपूल के रूप में कई थ्रेड बनाने चाहिए।

सामान्य वर्ग को नीचे की तरह लागू किया जाना चाहिए:

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

public class TimeoutThreadPoolDecorator extends ThreadPoolExecutor {


    private final ThreadPoolExecutor commandThreadpool;
    private final long timeout;
    private final TimeUnit unit;

    public TimeoutThreadPoolDecorator(ThreadPoolExecutor threadpool,
                                      long timeout,
                                      TimeUnit unit ){
        super(  threadpool.getCorePoolSize(),
                threadpool.getMaximumPoolSize(),
                threadpool.getKeepAliveTime(TimeUnit.MILLISECONDS),
                TimeUnit.MILLISECONDS,
                threadpool.getQueue());

        this.commandThreadpool = threadpool;
        this.timeout=timeout;
        this.unit=unit;
    }

    @Override
    public void execute(Runnable command) {
        super.execute(() -> {
            Future<?> future = commandThreadpool.submit(command);
            try {
                future.get(timeout, unit);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException | TimeoutException e) {
                throw new RejectedExecutionException(e);
            } finally {
                future.cancel(true);
            }
        });
    }

    @Override
    public void setCorePoolSize(int corePoolSize) {
        super.setCorePoolSize(corePoolSize);
        commandThreadpool.setCorePoolSize(corePoolSize);
    }

    @Override
    public void setThreadFactory(ThreadFactory threadFactory) {
        super.setThreadFactory(threadFactory);
        commandThreadpool.setThreadFactory(threadFactory);
    }

    @Override
    public void setMaximumPoolSize(int maximumPoolSize) {
        super.setMaximumPoolSize(maximumPoolSize);
        commandThreadpool.setMaximumPoolSize(maximumPoolSize);
    }

    @Override
    public void setKeepAliveTime(long time, TimeUnit unit) {
        super.setKeepAliveTime(time, unit);
        commandThreadpool.setKeepAliveTime(time, unit);
    }

    @Override
    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
        super.setRejectedExecutionHandler(handler);
        commandThreadpool.setRejectedExecutionHandler(handler);
    }

    @Override
    public List<Runnable> shutdownNow() {
        List<Runnable> taskList = super.shutdownNow();
        taskList.addAll(commandThreadpool.shutdownNow());
        return taskList;
    }

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

उपरोक्त डेकोरेटर का उपयोग नीचे किया जा सकता है:

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {

    public static void main(String[] args){

        long timeout = 2000;

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 10, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(true));

        threadPool = new TimeoutThreadPoolDecorator( threadPool ,
                timeout,
                TimeUnit.MILLISECONDS);


        threadPool.execute(command(1000));
        threadPool.execute(command(1500));
        threadPool.execute(command(2100));
        threadPool.execute(command(2001));

        while(threadPool.getActiveCount()>0);
        threadPool.shutdown();


    }

    private static Runnable command(int i) {

        return () -> {
            System.out.println("Running Thread:"+Thread.currentThread().getName());
            System.out.println("Starting command with sleep:"+i);
            try {
                Thread.sleep(i);
            } catch (InterruptedException e) {
                System.out.println("Thread "+Thread.currentThread().getName()+" with sleep of "+i+" is Interrupted!!!");
                return;
            }
            System.out.println("Completing Thread "+Thread.currentThread().getName()+" after sleep of "+i);
        };

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