programing

스레드 타임아웃 방법

goodsources 2022. 8. 10. 22:26
반응형

스레드 타임아웃 방법

일정한 시간 동안 스레드를 실행하고 싶다.만약 그 시간 내에 완성되지 않으면 죽이거나 예외를 두거나 어떻게든 처리하고 싶습니다.어떻게 할 수 있을까요?

스레드에서 알아낸 방법 중 하나는 스레드의 run() 메서드 내에서 TimerTask를 사용하는 것입니다.

이에 대한 더 나은 해결책은 없나요?

 
편집: 더 명확한 답변이 필요했기 때문에 현상금을 추가했습니다.이그제큐티브 서비스"sleep()" "sleep()" "sleep()"될 수 있습니까?코드가 완료되고 sleep()이 중단되면 어떻게 타임아웃이 될까요?

수행해야 할 작업은 내 마음대로 할 수 없다.모든 코드 조각이 될 수 있습니다.문제는 이 코드 조각이 무한 루프에 빠질 수 있다는 것입니다.그런 일이 일어나길 바라지 않아요.이 작업을 별도의 스레드로 실행하려고 합니다.상위 스레드는 해당 스레드가 완료될 때까지 기다려야 하며 작업 상태(타임아웃 또는 일부 예외가 발생했는지 또는 성공했는지 여부)를 알아야 합니다.업무가 무한 루프로 진입하게 되면, 내 부모 스레드 무기한 아닌 이상적인 상황 대기하고 있다.

실제로 오히려 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미래#get()법에 논쟁은, 예를 들어 5에 해당 스레드에서 끝나 보자 다시 증가.당신은에서 시간 초과를 가로챌 수 있다catch (TimeoutException e)를 누릅니다

:개념적인 오해, 명확히 하기 위해 Update를 설정합니다.sleep()필요하지 않다.그냥 SSCCE/demonstration 목적으로 사용된다.바로 거기서 장소에서 귀하의 긴 달리는 일을 시켰죠.sleep()경우 스레드는 모두 차단하지 않다 다음과 같다. 너의 긴 실행 과제 속에서:확인해야 한다.

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

에는 100%신뢰할 수 있는 방법 어떠한 오래 된 일을 위해 이런 일을 하지 않다.그 일은 마음 속에 이 능력을 가지고 쓰여져야 한다.

「」등의 .ExecutorService취소 비동기 작업은 작업자 스레드에서 interrupt()전화로.예를 들어 작업에 루프가 포함되어 있는 경우 각 반복에서 인터럽트 상태를 확인해야 합니다.작업이 I/O 작업을 수행하는 경우 작업 중단도 가능해야 합니다. 이 작업을 설정하는 것은 까다로울 수 있습니다.어떤 경우에도 코드는 인터럽트를 적극적으로 체크해야 합니다.인터럽트를 설정한다고 해서 반드시 아무것도 할 수 있는 것은 아닙니다.

물론 작업이 단순한 루프일 경우 반복할 때마다 현재 시간을 확인하고 지정된 타임아웃이 경과하면 포기할 수 있습니다.이 경우 작업자 스레드는 필요하지 않습니다.

ExecutorService 인스턴스 사용을 고려해 보십시오.둘다요.invokeAll() ★★★★★★★★★★★★★★★★★」invokeAny()는 메드 a a a a a a a a a a a a a a a로 할 수 .timeout파라미터를 지정합니다.

작업이 정상적으로 완료되었거나 시간 초과에 도달했기 때문에 현재 스레드는 메서드가 완료될 때까지 차단됩니다(이 방법이 바람직한지 확실하지 않음).된 것을 할 수 .Future 무슨 일이 일어났는지 하다.

스레드 코드가 관리 범위를 벗어났다고 가정하면:

위의 Java 매뉴얼에서 다음 순서를 수행합니다.

스레드가 스레드에 응답하지 않으면 어떻게 합니까?방해하고 있나요?

경우에 따라 응용 프로그램별 트릭을 사용할 수 있습니다.예를 들어, 스레드가 알려진 소켓에서 대기하고 있는 경우 소켓을 닫아 스레드가 즉시 반환되도록 할 수 있습니다.안타깝게도, 일반적으로 효과가 있는 기술은 없습니다.대기 중인 스레드가 스레드에 응답하지 않는 모든 상황에서는 주의해야 합니다.인터럽트, Thread.stop에도 응답하지 않습니다.이러한 예에는 의도적인 서비스 거부 공격과 스레드.정지 및 스레드 I/O 조작이 포함됩니다.인터럽트가 제대로 작동하지 않습니다.

결론:

모든 스레드가 중단될 수 있는지 확인하십시오. 그렇지 않으면 설정할 플래그가 있는 경우와 같이 스레드에 대한 특정 지식이 필요합니다.할 수 . 즉, 를 '정지'로 할 수 .stop().또한 태스크를 중지하지 못한 경우에도 경고할 수 있습니다.

BalusC는 다음과 같이 말했습니다.

업데이트: 개념적인 오해를 해소하기 위해 sleep()은 필요하지 않습니다.이것은 SSCE/데모를 목적으로만 사용됩니다.수면() 대신 장시간 실행 작업을 바로 수행할 수 있습니다.

, 「」를 치환하면,Thread.sleep(4000);for (int i = 0; i < 5E8; i++) {} 빈 안 컴파일이 안 요.빈 루프가 빈 루프를 던지지 않기 때문입니다.InterruptedException.

스레드가 , 그고 an an an, 것 an an an an an an an an an 던져야 합니다.InterruptedException

이것은 나에게 심각한 문제인 것 같다.일반적인 장기 실행 작업에서 이 답변을 어떻게 수정해야 할지 모르겠습니다.

추가하도록 편집됨:저는 이것을 새로운 질문으로 다시 물었습니다.[정해진 시간 후에 스레드를 중단하는 것은 중단되는 것을 던질 필요가 있는가?]예외?]

적절한 동시 처리 메커니즘에 대해 살펴봐야 한다고 생각합니다(무한 루프로 이어지는 스레드는 그 자체로 좋지 않습니다.btw)."죽이기" 또는 "정지" 스레드 항목에 대해 조금 읽어보십시오.

당신이 설명하는 것은 "렌데부"처럼 들리므로 CyclicBarrier를 보는 것이 좋습니다.

문제를 해결할 수 있는 다른 구성 요소(예를 들어 CountDownLatch 사용)가 있을 수 있습니다(예를 들어, 1개의 스레드가 타임아웃을 기다리고 있으면 다른 스레드가 래치다운됩니다).이 경우 타임아웃 후 또는 래치카운트다운이 호출되면 첫 번째 스레드가 해방됩니다.

이 분야에서는 보통 두 권의 책을 추천한다.Java에서의 동시 프로그래밍과 실무에서의 Java 동시 프로그래밍.

얼마 전에 이것 때문에 도우미 클래스를 만들었습니다.뛰어난 기능:

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

문제를 해결하는 방법을 보여주는 코드를 하나 게시합니다.예를 들어, 나는 파일을 읽고 있다.이 메서드는 다른 조작에 사용할 수 있지만 메인 조작이 중단되도록 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;
    }

}

BalusC가 제공하는 솔루션에서는 메인 스레드는 타임아웃 기간 동안 차단된 상태로 유지됩니다.스레드가 여러 개 있는 스레드 풀이 있는 경우 Future.get(롱타임아웃)을 사용하는 스레드와 동일한 수의 추가 스레드가 필요합니다.TimeUnit 유닛)이 타임아웃 기간을 넘으면 대기하고 스레드를 닫는 콜을 차단합니다.

이 문제에 대한 일반적인 해결책은 타임아웃 기능을 추가할 수 있는 ThreadPoolExecutor 데코레이터를 작성하는 것입니다.이 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);
        };

    }
}

다음 스니펫은 별도의 스레드에서 작업을 시작한 후 작업이 완료될 때까지 최대 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의 훌륭한 답변:

단, 타임아웃 자체는 스레드 자체를 중단시키지 않습니다.(!)에 체크하고 있어도,Thread.interrupted()를 선택합니다.스레드가 정지하고 있는 것을 확인하려면 , 타임 아웃 예외가 검출되었을 때에 future.timeout()이 기동되고 있는 것도 확인해 주세요.

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

그 답은 주로 업무 자체에 달려 있다고 생각합니다.

  • 하나의 작업을 반복하고 있습니까?
  • 타임아웃이 만료되면 즉시 현재 실행 중인 작업을 중단해야 합니까?

첫 번째 답변이 예이고 두 번째 답변이 아니오인 경우 다음과 같이 단순하게 할 수 있습니다.

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

이것이 선택사항이 아닌 경우, 요건을 좁히거나 코드를 제시해 주십시오.

실행 시간 초과된 모든 실행 가능 실행을 중단할 수 있는 실행 서비스(Executor Service)를 찾고 있었지만 찾을 수 없었습니다.몇 시간 후 아래와 같이 작성했습니다.이 클래스는 견고성을 높이기 위해 변경할 수 있습니다.

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

이제, 나는 이런 문제를 만난다.그것은 우연히 사진을 해독한다.디코딩 처리 시간이 너무 오래 걸려서 화면이 검게 유지됩니다.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
    }

언급URL : https://stackoverflow.com/questions/2275443/how-to-timeout-a-thread

반응형