Как отключить поток
Я хочу запустить поток в течение определенного промежутка времени. Если он не будет завершен в течение этого времени, я хочу либо убить его, либо выдать какое-то исключение, либо как-то обработать его. Как это можно сделать?
Как я понял из этого потока, один из способов сделать это - использовать TimerTask внутри метода run() потока.
Есть ли лучшие решения для этого?
РЕДАКТИРОВАТЬ: Добавление щедрости, как мне нужно более четкий ответ. Приведенный ниже код ExecutorService не решает мою проблему. Почему я должен спать () после выполнения (некоторый код - у меня нет никакого контроля над этим куском кода)? Если код завершен, а sleep() прерван, как это может быть timeOut?
Задача, которую нужно выполнить, не в моем контроле. Это может быть любой кусок кода. Проблема в том, что этот кусок кода может попасть в бесконечный цикл. Я не хочу, чтобы это случилось. Итак, я просто хочу запустить эту задачу в отдельном потоке. Родительский поток должен ждать, пока этот поток не завершится, и должен знать состояние задачи (т. Е. Истекло ли время или произошло какое-то исключение, или если оно выполнено успешно). Если задача входит в бесконечный цикл, мой родительский поток продолжает ждать бесконечно, что не является идеальной ситуацией.
18 ответов
Действительно лучше использовать ExecutorService
вместо Timer
вот SSCCE:
package com.stackru.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.
}
Не существует 100% надежного способа сделать это для любой старой задачи. Задача должна быть написана с учетом этой способности.
Основные библиотеки Java, такие как ExecutorService
отменить асинхронные задачи с interrupt()
звонки на рабочий поток. Так, например, если задача содержит какой-то цикл, вы должны проверять ее состояние прерывания на каждой итерации. Если задача выполняет операции ввода-вывода, они также должны быть прерываемыми, и их настройка может быть сложной. В любом случае имейте в виду, что код должен активно проверять наличие прерываний; установка прерывания не обязательно делает что-либо.
Конечно, если ваша задача представляет собой какой-то простой цикл, вы можете просто проверять текущее время на каждой итерации и сдаваться по истечении заданного времени ожидания. В этом случае рабочий поток не нужен.
Рассмотрите возможность использования экземпляра ExecutorService. И то и другое invokeAll()
а также invokeAny()
методы доступны с timeout
параметр.
Текущий поток будет блокироваться до тех пор, пока метод не завершится (не уверен, если это желательно), либо потому, что задача (и) выполнена нормально, либо истекло время ожидания. Вы можете проверить возвращенный Future
(ы), чтобы определить, что произошло.
Предполагая, что код потока находится вне вашего контроля:
Из документации Java, упомянутой выше:
Что если поток не отвечает на Thread.interrupt?
В некоторых случаях вы можете использовать специальные приемы приложения. Например, если поток ожидает известного сокета, вы можете закрыть сокет, чтобы поток немедленно вернулся. К сожалению, на самом деле нет какой-либо техники, которая работает в целом. Следует отметить, что во всех ситуациях, когда ожидающий поток не отвечает на Thread.interrupt, он также не отвечает на Thread.stop. Такие случаи включают в себя преднамеренные атаки типа "отказ в обслуживании" и операции ввода-вывода, для которых thread.stop и thread.interrupt не работают должным образом.
Нижняя линия:
Убедитесь, что все потоки могут быть прерваны, или же вам нужны специальные знания о потоке - например, наличие установленного флага. Может быть, вы можете потребовать, чтобы вам было дано задание вместе с кодом, необходимым для его остановки - определите интерфейс с stop()
метод. Вы также можете предупредить, когда вам не удалось остановить задачу.
BalusC сказал:
Обновление: чтобы прояснить концептуальное недоразумение, сон () не требуется. Это просто используется для SSCCE/ демонстрационных целей. Просто сделайте свою долгосрочную задачу прямо там, где спите ().
Но если вы замените Thread.sleep(4000);
с for (int i = 0; i < 5E8; i++) {}
тогда он не компилируется, потому что пустой цикл не выбрасывает InterruptedException
,
И чтобы поток был прерываемым, он должен бросить InterruptedException
,
Это кажется серьезной проблемой для меня. Я не вижу, как адаптировать этот ответ для работы с общей долгосрочной задачей.
Отредактировано, чтобы добавить: я переосмыслил это как новый вопрос: [ прерывание потока через фиксированное время, должно ли оно генерировать InterruptedException? ]
Я создал вспомогательный класс только для этого некоторое время назад. Работает отлично:
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) {}
Я думаю, что вы должны взглянуть на правильные механизмы обработки параллелизма (потоки, работающие в бесконечные циклы, сами по себе не кажутся хорошими, кстати). Убедитесь, что вы прочитали немного о теме "убийства" или "остановки" темы.
То, что вы описываете, звучит очень похоже на "свидание", так что вы можете взглянуть на CyclicBarrier.
Могут быть и другие конструкции (например, с использованием CountDownLatch), которые могут решить вашу проблему (один поток ожидает с тайм-аутом для защелки, другой должен отсчитывать защелку, если он выполнил свою работу, которая освободит ваш первый поток либо после тайм-аут или когда вызывается отсчет защелки).
Я обычно рекомендую две книги в этой области: параллельное программирование на Java и параллелизм на практике.
В решении, предоставленном BalusC, основной поток остается заблокированным в течение периода ожидания. Если у вас есть пул потоков с более чем одним потоком, вам потребуется то же количество дополнительных потоков, которые будут использовать блокирующий вызов Future.get (long timeout, TimeUnit unit) для ожидания и закрытия потока, если он превышает период времени ожидания.
Общее решение этой проблемы состоит в создании ThreadPoolExecutor Decorator, который может добавить функцию тайм-аута. Этот класс Decorator должен создать столько потоков, сколько имеется в ThreadPoolExecutor, и все эти потоки следует использовать только для ожидания и закрытия ThreadPoolExecutor.
Универсальный класс должен быть реализован как показано ниже:
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);
};
}
}
Я отправляю вам фрагмент кода, который показывает способ решения проблемы. В качестве примера я читаю файл. Вы можете использовать этот метод для другой операции, но вам нужно реализовать метод kill(), чтобы основная операция была прервана.
Надеюсь, поможет
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!");
}
}
}
С уважением
Вот мой действительно простой в использовании вспомогательный класс для запуска или вызова части кода Java:-)
Это основано на превосходном ответе от 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;
}
}
Следующий фрагмент запускает операцию в отдельном потоке, затем ждет до 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()
для пула потоков без верхнего предела количества потоков.
Одна вещь, о которой я не упомянул, это то, что убийство потоков - это, как правило, плохая идея. Существуют методы для того, чтобы сделать потоковые методы полностью прерываемыми, но это отличается от простого уничтожения потока после истечения времени ожидания.
Риск того, что вы предлагаете, заключается в том, что вы, вероятно, не знаете, в каком состоянии будет поток, когда вы его убьете, поэтому вы рискуете ввести нестабильность. Лучшее решение - убедиться, что ваш многопоточный код либо не зависает, либо будет хорошо отвечать на запрос об отмене.
Отличный ответ от BalusC:
но просто добавлю, что сам тайм-аут не прерывает сам поток. даже если вы проверяете с помощью while(!Thread.interrupted()) в своей задаче. если вы хотите убедиться, что поток остановлен, вы также должны убедиться, что future.cancel() вызывается, когда исключение тайм-аута перехватывается.
package com.stackru.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!!");
}
}
}
Я искал ExecutorService, который может прервать все тайм-ауты Runnable, выполненные им, но не нашел ни одного. Через несколько часов я создал один, как показано ниже. Этот класс может быть изменен для повышения надежности.
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();
}
Я бы предложил использовать метод опроса с параметром тайм-аута.ExecutorCompletionService
внутренне используетLinkedBlockingQueue
за выполненные задачи.
ExecutorService executorService = Executors.newFixedThreadPool(1);
ExecutorCompletionService executorCompletionService = new ExecutorCompletionService(executorService);
executorCompletionService.submit(() - > yourTask());
Future<ReturnType> future = executorCompletionService.poll(yourTimeout, TimeUnit.SECONDS);
if (Objects.isNull(future)) {
// Here future is null, it means your task was not completed within the given time.
}
Приведенный выше фрагмент кода предназначен дляCallable<ReturnType>
, если ваша задачаRunnable
тогда вы можете использоватьexecutorCompletionService.submit(() - > yourTask(), yourReturnObject)
Я думаю, что ответ в основном зависит от самой задачи.
- Делает ли это одно задание снова и снова?
- Необходимо ли, чтобы тайм-аут прерывал текущую задачу сразу же после ее истечения?
Если первый ответ - да, а второй - нет, вы можете сделать это так просто:
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();
}
}
Если это не вариант, сузьте ваши требования или покажите какой-нибудь код.
Теперь я столкнулся с такой проблемой. Это происходит, чтобы декодировать изображение. Процесс декодирования занимает слишком много времени, чтобы экран оставался черным. 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);
У меня такая же проблема. Поэтому я пришел к такому простому решению.
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
}