wake-up-neo.com

Wie lege ich einen Thread ab?

Ich möchte einen Thread für eine bestimmte Zeit ausführen. Wenn es nicht innerhalb dieser Zeit abgeschlossen ist, möchte ich es entweder töten, eine Ausnahme auslösen oder irgendwie damit umgehen. Wie geht das?

Eine Möglichkeit, wie ich aus diesem Thread Herausgefunden habe, ist die Verwendung einer TimerTask innerhalb der run () - Methode des Threads.

Gibt es dafür bessere Lösungen?


EDIT: Hinzufügen einer Prämie, da ich eine klarere Antwort brauchte. Der unten angegebene ExecutorService-Code spricht mein Problem nicht an. Warum sollte ich nach der Ausführung schlafen () (etwas Code - ich habe keinen Code für diesen Code)? Wenn der Code abgeschlossen ist und das sleep () unterbrochen ist, wie kann dies eine timeOut sein?

Die Aufgabe, die ausgeführt werden muss, liegt nicht in meiner Kontrolle. Es kann ein beliebiger Code sein. Das Problem ist, dass dieser Code in eine Endlosschleife geraten könnte. Ich möchte nicht, dass das passiert. Also möchte ich diese Aufgabe nur in einem separaten Thread ausführen. Der übergeordnete Thread muss warten, bis der Thread beendet ist, und er muss den Status der Aufgabe kennen (d. H. Ob er abgelaufen ist oder eine Ausnahme aufgetreten ist oder ob er erfolgreich ist). Wenn die Aufgabe in eine Endlosschleife übergeht, wartet mein übergeordneter Thread auf unbestimmte Zeit, was keine ideale Situation ist.

234
java_geek

Verwenden Sie in der Tat lieber ExecutorService anstelle von Timer, hier ist ein 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!";
    }
}

Spielen Sie ein bisschen mit dem Argument timeout in der Methode Future#get() , z. Wenn Sie den Wert auf 5 erhöhen, wird der Thread beendet. Sie können das Timeout im Block catch (TimeoutException e) abfangen.

Update: Um ein konzeptionelles Missverständnis zu klären, ist die sleep() nicht erforderlich . Es wird nur für SSCCE/Demonstrationszwecke verwendet. Erledige deine lang laufende Aufgabe genau dort anstelle von sleep(). In Ihrer lang laufenden Aufgabe sollten Sie überprüfen, ob der Thread nicht nterbrochen ist, wie folgt:

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

Es gibt keine 100% zuverlässige Möglichkeit, dies für alle alten Aufgaben zu tun. Die Aufgabe muss unter Berücksichtigung dieser Fähigkeit geschrieben werden.

Core-Java-Bibliotheken wie ExecutorService stornieren asynchrone Tasks mit interrupt() -Aufrufen im Worker-Thread. Wenn die Task beispielsweise eine Art Schleife enthält, sollten Sie ihren Interrupt-Status bei jeder Iteration überprüfen. Wenn die Task E/A-Vorgänge ausführt, sollten sie auch unterbrechbar sein - und das Einstellen kann schwierig sein. Beachten Sie auf jeden Fall, dass der Code aktiv auf Interrupts überprüft werden muss. Das Setzen eines Interrupts tut nicht unbedingt etwas.

Wenn es sich bei Ihrer Aufgabe um eine einfache Schleife handelt, können Sie einfach die aktuelle Uhrzeit bei jeder Iteration überprüfen und aufgeben, wenn ein angegebenes Timeout abgelaufen ist. Ein Arbeitsthread wird in diesem Fall nicht benötigt.

44
erickson

Erwägen Sie die Verwendung einer Instanz von ExecutorService . Beide invokeAll()- und invokeAny()-Methoden sind mit einem timeout-Parameter verfügbar. 

Der aktuelle Thread wird blockiert, bis die Methode abgeschlossen ist (nicht sicher, ob dies wünschenswert ist), entweder weil die Aufgabe (n) normal abgeschlossen wurden oder das Zeitlimit erreicht wurde. Sie können die zurückgegebenen Future (s) überprüfen, um festzustellen, was passiert ist.

13
Drew Wills

BalusC sagte:

Update: Um ein konzeptionelles Missverständnis zu klären, ist das sleep () nicht erforderlich. Es wird nur für SSCCE/Demonstrationszwecke verwendet. Machen Sie einfach Ihre langwierige Aufgabe anstelle von sleep ().

Wenn Sie jedoch Thread.sleep(4000); durch for (int i = 0; i < 5E8; i++) {} ersetzen, wird es nicht kompiliert, da die leere Schleife keine InterruptedException auslöst.

Und damit der Thread unterbrechbar ist, muss er eine InterruptedException werfen. 

Dies scheint mir ein ernstes Problem zu sein. Ich kann nicht erkennen, wie ich diese Antwort an die Arbeit mit einer allgemein lang andauernden Aufgabe anpassen kann. 

Zum Hinzufügen hinzugefügt: Ich habe dies als eine neue Frage erneut betrachtet: [ einen Thread nach einer festgelegten Zeit unterbrechen, muss InterruptedException ausgelöst werden? ]

8
user1310503

Angenommen, der Thread-Code liegt außerhalb Ihrer Kontrolle:

Aus der oben genannten Java Dokumentation :

Was ist, wenn ein Thread nicht auf Thread.interrupt reagiert?

In einigen Fällen können Sie anwendungsspezifische Tricks verwenden. Zum Beispiel, Wenn ein Thread auf einen bekannten Socket wartet, können Sie den Socket auf .__ schließen. veranlassen, dass der Thread sofort zurückkehrt. Leider gibt es wirklich ist keine Technik, die im Allgemeinen funktioniert. Es sollte beachtet werden, dass in Alle Situationen, in denen ein wartender Thread nicht auf Thread.interrupt reagiert, er auch nicht auf Thread.stop reagiert. So Fälle umfassen vorsätzliche Denial-of-Service-Angriffe und E/A-Vorgänge für welchen thread.stop und thread.interrupt nicht richtig funktionieren.

Endeffekt:

Stellen Sie sicher, dass alle Threads unterbrochen werden können. Andernfalls benötigen Sie spezielle Kenntnisse über den Thread, z. B. das Setzen eines Flags. Möglicherweise können Sie verlangen, dass die Aufgabe zusammen mit dem zum Beenden erforderlichen Code an Sie übergeben wird. Definieren Sie eine Schnittstelle mit einer stop()-Methode. Sie können auch warnen, wenn Sie eine Aufgabe nicht angehalten haben.

7
Peter Tseng

Dafür habe ich vor einiger Zeit eine Helferklasse erstellt. Funktioniert super: 

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

        }

    }
}

Es heißt so:

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) {}  
5
Peter Goransson

Ich denke, Sie sollten einen Blick auf die richtigen Mechanismen für die gleichzeitige Handhabung werfen (Threads, die in Endlosschleifen laufen, klingen an sich nicht gut, übrigens). Stellen Sie sicher, dass Sie ein wenig über das Thema "töten" oder "stoppen" von Threads lesen.

Was Sie beschreiben, klingt sehr nach einem "Rendezvous", so dass Sie einen Blick auf CyclicBarrier werfen möchten.

Möglicherweise gibt es andere Konstrukte (z. B. CountDownLatch ), die das Problem lösen können (ein Thread wartet mit einem Timeout auf den Latch, der andere sollte den Latch herunterzählen, wenn er seine Arbeit erledigt hat, was seine Arbeit freigibt erster Thread entweder nach einem Timeout oder wenn der Latch-Countdown aufgerufen wird).

Ich empfehle normalerweise zwei Bücher in diesem Bereich: Concurrent Programming in Java und Java Concurrency in Practice .

5
Dieter

Ich poste Ihnen einen Code, der zeigt, wie das Problem gelöst werden kann. Beispiel: Ich lese eine Datei ... Sie können diese Methode für eine andere Operation verwenden, aber Sie müssen das kill () implementieren Methode, so dass die Hauptoperation unterbrochen wird.

ich hoffe es hilft


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

Grüße

3
elou

Eine Sache, die ich nicht erwähnt habe, ist, dass das Töten von Threads im Allgemeinen eine schlechte Idee ist. Es gibt Techniken zum Erstellen von Thread-Methoden sauber abbruchsfähig , aber das unterscheidet sich davon, einen Thread nach einem Timeout zu beenden.

Das Risiko bei dem, was Sie vorschlagen, ist, dass Sie wahrscheinlich nicht wissen, in welchem ​​Zustand sich der Thread befindet, wenn Sie ihn abtöten - also riskieren Sie Instabilität. Eine bessere Lösung besteht darin, sicherzustellen, dass der Thread-Code sich entweder nicht selbst hängt oder auf eine Abbruchanforderung gut reagiert.

2
Dan Puzey

Große Antwort von BalusC: 

nur um hinzuzufügen, dass der Timeout selbst den Thread selbst nicht unterbricht. Auch wenn Sie mit while (! Thread.interrupted ()) in Ihrer Aufgabe überprüfen. Wenn Sie sicherstellen möchten, dass der Thread gestoppt wird, sollten Sie auch sicherstellen, dass future.cancel () aufgerufen wird, wenn die Timeout-Ausnahme catch ist.

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!!");
      }          
    } 
} 
2
Robocide

Hier ist meine wirklich einfach zu verwenden Hilfsklasse zu run oder call Stück Java-Code :-)

Dies basiert auf der hervorragenden Antwort von 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
Pascal

Das folgende Snippet startet einen Vorgang in einem separaten Thread und wartet dann bis zu 10 Sekunden, bis der Vorgang abgeschlossen ist. Wenn der Vorgang nicht rechtzeitig abgeschlossen ist, versucht der Code, den Vorgang abzubrechen, und fährt dann auf seine lustige Weise fort. Selbst wenn der Vorgang nicht einfach abgebrochen werden kann, wartet der übergeordnete Thread nicht auf den Abschluss des untergeordneten Threads.

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
}

Die getExecutorService()-Methode kann auf verschiedene Arten implementiert werden. Wenn Sie keine besonderen Anforderungen haben, können Sie einfach Executors.newCachedThreadPool() für das Thread-Pooling ohne Obergrenze für die Anzahl der Threads aufrufen.

2
markusk

Ich denke, die Antwort hängt hauptsächlich von der Aufgabe selbst ab.

  • Tut es immer wieder eine Aufgabe? 
  • Ist es notwendig, dass das Timeout eine aktuell ausgeführte Task unmittelbar nach deren Ablauf abbricht?

Wenn die erste Antwort ja ist und die zweite nein ist, können Sie es so einfach wie folgt halten:

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

Wenn dies keine Option ist, beschränken Sie bitte Ihre Anforderungen - oder zeigen Sie Code.

0
sfussenegger

Nun habe ich ein Problem wie dieses. Es passiert ein Bild zu decodieren. Die Dekodierung dauert zu lange, bis der Bildschirm schwarz bleibt. Ich füge einen Zeitsteuerer hinzu: Wenn die Zeit zu lang ist, dann rufen Sie den aktuellen Thread auf.

   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
Liu Jing

Ich habe nach einem ExecutorService gesucht, der alle von ihm ausgeführten Zeitüberschreitungen unterbrechen kann, aber keine gefunden hat. Nach ein paar Stunden habe ich eine wie unten erstellt. Diese Klasse kann zur Verbesserung der Robustheit geändert werden.

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

Verwendungszweck:

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
Tom

In der von BalusC angegebenen Lösung bleibt der Haupt-Thread für die Zeitüberschreitung blockiert. Wenn Sie über einen Thread-Pool mit mehr als einem Thread verfügen, benötigen Sie dieselbe Anzahl zusätzlicher Threads, die Future.get (langer Timeout-Vorgang, TimeUnit-Einheit) blockieren, um zu warten und den Thread zu schließen, wenn er überschritten wird die Auszeit. 

Eine generische Lösung für dieses Problem ist das Erstellen eines ThreadPoolExecutor Decorator, der die Timeout-Funktionalität hinzufügen kann. Diese Decorator-Klasse sollte so viele Threads erstellen, wie ThreadPoolExecutor hat, und alle diese Threads sollten nur zum Warten und Schließen des ThreadPoolExecutor verwendet werden.

Die generische Klasse sollte wie folgt implementiert werden:

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

Der obige Dekorateur kann wie folgt verwendet werden:

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

    }
}
0
Sumeet Sahu

Ich hatte das gleiche Problem. Ich habe mir so eine einfache Lösung ausgedacht. 

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

Garantiert, dass der Block nicht innerhalb der gesetzten Frist ausgeführt wurde. Der Prozess wird beendet und eine Ausnahme ausgelöst.

beispiel:

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
    }