스레드 시간 초과 방법 사용하는 것입니다. 더 나은 해결책이 있습니까?   편집 : 명확한

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

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

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

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

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



답변

실제로 오히려 사용하는 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.
}


답변

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

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

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


답변

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

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


답변

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

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

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

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

결론 :

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


답변

BalusC는 말했다 :

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

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

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

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

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


답변

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

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

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

나는 보통이 영역 에서 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) {}