스레드 시간 초과 방법


255

일정 시간 동안 스레드를 실행하고 싶습니다. 그 시간 내에 완료되지 않으면 죽이거나 예외를 던지거나 어떤 식 으로든 처리하고 싶습니다. 어떻게 할 수 있습니까?

이 스레드 에서 알아 낸 한 가지 방법은 Thread 의 run () 메서드 내에서 TimerTask를 사용하는 것입니다.

더 나은 해결책이 있습니까?

 
편집 : 명확한 대답이 필요하여 현상금 추가. 아래의 ExecutorService 코드는 내 문제를 해결하지 못합니다. 실행 후 왜 sleep ()해야합니까 (일부 코드-이 코드를 처리하지 못함)? 코드가 완료되고 sleep ()이 중단되면 어떻게 timeOut이 될 수 있습니까?

실행해야 할 작업이 내가 통제 할 수 없습니다. 모든 코드 조각이 될 수 있습니다. 문제는이 코드 조각이 무한 루프에 빠질 수 있다는 것입니다. 나는 그런 일이 일어나고 싶지 않습니다. 그래서 나는 그 작업을 별도의 스레드에서 실행하고 싶습니다. 부모 스레드는 해당 스레드가 완료 될 때까지 기다려야하며 작업 상태 (예 : 시간 초과 또는 예외 발생 여부 또는 성공 여부)를 알아야합니다. 작업이 무한 루프 상태가되면 부모 스레드가 무기한 대기 상태를 유지하므로 이상적인 상황이 아닙니다.


편집 : 더 명확한 답변이 필요로 현상금을 추가합니다. 아래의 ExecutorService 코드는 내 문제를 해결하지 못합니다. 코드를 실행 한 후 왜 sleep ()해야합니까? 코드가 완료되고 sleep ()이 중단되면 어떻게 timeOut이 될 수 있습니까?
java_geek

7
그것은 sleep()"장시간 실행 작업"을 나타내는 스텁입니다. 실제 작업으로 바꾸십시오.;)
BalusC

1
... interrupt()스레드 에서 호출에 응답하는 "장시간 실행 작업"입니다. 모든 "차단"호출이 수행하는 것은 아닙니다. 중단하려는 작업의 세부 사항은 사용해야하는 접근 방식에 큰 차이를 만듭니다. 작업에 대한 자세한 정보가 도움이 될 것입니다.
erickson

이 답변으로 문제가 해결되지 않으면 자세한 내용 / 코드가 도움이 될 것입니다.
Elister

시간 제한하려는 스레드입니다. 그들이 전화를 걸고 있습니까, 아니면 어떤 변수를 쉽게 종료 할 시간인지 확인할 수있는 루프에 있습니까?
Scott Smith

답변:


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)다른 장기 실행 문 및 예제가 작동하지 않습니다. 즉,이 예제는 상태 변경 을 이해하도록 설계된 경우 에만 작동 합니다 . TaskThread.isInterrupted()
yegor256

@BalusC 나는이 접근법을 시도하여 스레드를 종료하려고 시도했지만 작동시키지 못했습니다. 당신은 여기에서 확인할 수 있습니다 : stackoverflow.com/questions/35553420/...
syfantid

future.cancel (true)에 의해 중단 된 InterruptedException은 어떻게 처리됩니까?
bolei

1
n 명의 사람들이 패키지 이름에 대해 언급했으며 여기에 또 하나의 +1이 있습니다. 그것은 아주 좋은 기술입니다. 감사!
Ashwin Tumma

@BalusC 미래가 동기식으로 실행 될지 여부와 의심의 여지가 있습니다. 미리 정의 된 시간보다 오래 걸리면 종료됩니다. 그렇지 않으면 우리가 시간을 계산하는 사이에 약간의 시간이 ... 감사 미래에 실행하는 것
Adeel 아마드

49

오래된 작업에 대해 100 % 신뢰할 수있는 방법은 없습니다. 이 능력을 염두에두고 과제를 작성해야합니다.

작업자 스레드에서 호출을 사용하여 ExecutorService비동기 작업 취소 와 같은 핵심 Java 라이브러리 interrupt(). 예를 들어, 작업에 일종의 루프가 포함 된 경우 각 반복에서 인터럽트 상태 를 확인해야합니다 . 작업이 I / O 작업을 수행하는 경우에도 인터럽트 가능해야하며 설정이 까다로울 수 있습니다. 어쨌든 코드는 인터럽트를 적극적으로 확인해야합니다. 인터럽트를 설정한다고해서 반드시 아무것도하는 것은 아닙니다.

물론 작업이 간단한 루프 인 경우 각 반복에서 현재 시간을 확인하고 지정된 시간 초과가 경과하면 포기할 수 있습니다. 이 경우 작업자 스레드가 필요하지 않습니다.


내 경험상 인터럽트를 시작하기 위해 반응하지 않는 유일한 코드는 네이티브 코드를 차단하는 것입니다 (운영 체제를 기다리는 중).
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen 동의하지만 많은 코드입니다. 내 요점은 이것에 대한 범용 메커니즘이 없다는 것입니다. 작업 중단 정책을 이해해야합니다.
erickson

@erickson, 나는 당신의 의견에 동의합니다. 요컨대, 각 작업에 대해 취소 정책을 정의하려면 중지 정책이 있어야합니다. 또는 스레드는 인터럽트 될 때 수행해야 할 작업을 알고 있어야합니다. 결국 스레드 중단 및 중지는 대상 스레드가 수락하거나 거부 할 수있는 요청이므로이를 염두에두고 작업을 작성하는 것이 좋습니다.
AKS

executorservice가 호출 스레드에서 태스크를 실행하도록 선택할 수 없습니까? 또한 executorservice는 나중에 언젠가 작업을 실행하도록 선택할 수 있습니까?
filthy_wizard

@ user1232726 execute()부모 인터페이스 의 메소드 Executor는 호출 스레드에서 작업을 실행할 수 있습니다. 그 반환 submit()방법에 대한 비슷한 진술이 없습니다.ExecutorServiceFuture 인스턴스 . 서비스의 의미는 종료를 통해 정리해야하는 작업자 스레드가 있고 작업이 비동기 적으로 실행된다는 것입니다. 그러나 계약서 ExecutorService에는 제출 스레드에서 작업을 실행할 수 없다고 말하는 내용 이 없습니다. 이러한 보증은 Executors팩토리 와 같은 구현 API에서 제공 됩니다.
erickson

13

ExecutorService 인스턴스 사용을 고려하십시오 . 모두 invokeAll()invokeAny()방법은 사용할 수 있습니다 timeout매개 변수입니다.

작업이 정상적으로 완료되었거나 시간 초과에 도달하여 메서드가 완료 될 때까지 (현재 상황이 확실하지 않은 경우) 현재 스레드가 차단됩니다. 반환 된 내용을 검사하여 Future무슨 일이 있었는지 확인할 수 있습니다 .


9

스레드 코드가 제어 할 수 없다고 가정합니다.

위에서 언급 한 Java 문서에서 :

스레드가 Thread.interrupt에 응답하지 않으면 어떻게됩니까?

경우에 따라 응용 프로그램 별 트릭을 사용할 수 있습니다. 예를 들어, 스레드가 알려진 소켓에서 대기중인 경우 소켓을 닫아 스레드가 즉시 리턴되도록 할 수 있습니다. 불행히도 실제로는 일반적으로 작동하는 기술이 없습니다. 대기중인 스레드가 Thread.interrupt에 응답하지 않는 모든 상황에서 Thread.stop에도 응답하지 않습니다. 이러한 경우에는 의도적 인 서비스 거부 공격과 thread.stop 및 thread.interrupt가 제대로 작동하지 않는 I / O 작업이 포함됩니다.

결론 :

모든 스레드가 중단 될 수 있는지 또는 플래그 설정과 같이 스레드에 대한 특정 지식이 필요합니다. 어쩌면 태스크를 중지하는 데 필요한 코드와 함께 태스크를 제공해야 할 수도 있습니다 stop(). 메소드 로 인터페이스를 정의하십시오 . 작업을 중지하지 못한 경우 경고 할 수도 있습니다.


8

BalusC는 말했다 :

업데이트 : 개념적 오해를 명확히하기 위해 sleep ()이 필요하지 않습니다. SSCCE / 데모 설명 용도로만 사용됩니다. sleep () 대신 장기 실행 작업을 바로 수행하십시오.

당신은 대체하지만 Thread.sleep(4000);함께 for (int i = 0; i < 5E8; i++) {}빈 루프가 던져하지 않기 때문에 그것은, 컴파일되지 않습니다 InterruptedException.

스레드가 인터럽트 가능하도록하려면을 던져야합니다 InterruptedException.

이것은 나에게 심각한 문제처럼 보인다. 장기적으로 실행되는 일반적인 작업에서이 답변을 어떻게 적용 할 수 있는지 알 수 없습니다.

추가 편집 : 나는 이것을 새로운 질문으로 재발 명했다 : [ 고정 시간 후에 스레드를 중단하면 InterruptedException을 발생시켜야합니까? ]


내가하는 방법은 public Class <T> call {} 메소드에 'throws Exception'을 추가하는 것입니다.
Roberto Linares

5

적절한 동시 처리 메커니즘을 살펴 봐야한다고 생각합니다 (무한 루프로 실행되는 스레드는 그 자체로는 좋지 않습니다, btw). "킬링"또는 "중지"스레드에 대해 조금 읽어보십시오 주제에 .

당신이 묘사하는 것은 "랑데부"와 매우 흡사하므로 CyclicBarrier를 살펴보고 싶을 것입니다 .

CountDownLatch 사용과 같은 다른 구문이있을 수 있습니다.문제를 해결할 예 : )이있을 수 있습니다 (하나의 스레드는 래치 시간 초과로 대기하고 다른 하나는 래치가 작동하면 래치를 카운트 다운해야합니다. 타임 아웃 또는 래치 카운트 다운이 호출 될 때).

나는 보통이 영역 에서 Java의 동시 프로그래밍Java 동시성 연습의 두 권의 책을 추천 합니다.


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

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

문안 인사


3

다음은 헬퍼 클래스 를 사용 하여 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;
    }

}

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()스레드 수에 대한 상한없이 스레드 풀링을 간단히 호출 할 수 있습니다 .


수입품은 무엇입니까? 무엇 SomeClassFuture?
ADTC

2

내가 언급하지 않은 한 가지는 스레드를 죽이는 것이 일반적으로 나쁜 생각이라는 것입니다. 스레드 메소드를 깨끗하게 중단 시키는 기술이 있지만 시간 초과 후 스레드를 종료하는 것과는 다릅니다.

당신이 제안하는 것의 위험은 스레드를 죽일 때 스레드가 어떤 상태에 있는지 알지 못하는 것이므로 불안정성을 초래할 위험이 있습니다. 더 나은 해결책은 스레드 코드가 멈추지 않거나 중단 요청에 잘 응답하는지 확인하는 것입니다.


문맥이 없으면 당신과 같은 말이 너무 제한적으로 들립니다. 학업 환경에서 나는 종종 타임 아웃까지 무언가를 테스트해야 할 필요성이 생겼으며, 그것이 일어날 때 나는 단순히 모든 계산을 버리고 타임 아웃이 발생한 것을 기록합니다. 아마 업계에서는 드물지만 여전히 ...
Alessandro S.

@AlessandroS : OP는 "더 나은 솔루션"을 요구했지만 합리적인 견해입니다.이를 통해 무차별 대입보다 견고성과 신뢰성이 선호됩니다.
Dan Puzey

2

BalusC의 훌륭한 답변 :

그러나 타임 아웃 자체가 스레드 자체를 방해하지 않는다는 것을 추가하기 만하면됩니다. 작업에서 while (! Thread.interrupted ())로 확인하더라도. 스레드가 중지되도록하려면 제한 시간 초과 예외가 발견 될 때 future.cancel ()이 호출되는지 확인해야합니다.

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

실행 된 모든 시간 초과 Runnables를 중단 할 수있는 ExecutorService를 찾고 있었지만 아무것도 찾지 못했습니다. 몇 시간 후 나는 아래와 같이 하나를 만들었습니다. 이 클래스는 견고성을 향상시키기 위해 수정 될 수 있습니다.

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

    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.