2010-04-28 19 views
26

Java에서 지정된 시간 제한 후 하위 스레드를 죽일 방법이 있습니까? 편집 : 또한이 특정 스레드가 최악의 경우 차단 될 수 있습니다 (스레드는 파일 수정을 기다리는 데 사용되며이 이벤트가 발생할 때까지 차단됨). 따라서 interrupt()가 성공적인지 확실하지 않습니다.Java에서 지정된 시간 제한 후 스레드를 죽이는

+0

파일 수정? Object.wait() 또는 다른 것? – mdma

+0

사실 jpathwatch를 사용하여 파일 수정 사항을 찾고 특히 'watchService.take()'는 파일이 작성/삭제 될 때까지 차단됩니다. – Traker

답변

33

Runnable을 실행하려면 ExecutorService을 사용하고, 시간 초과를 지정할 수있는 방법을 확인하십시오. 예 : 물론

ExecutorService executor = Executors.newSingleThreadExecutor(); 
executor.invokeAll(Arrays.asList(new Task()), 10, TimeUnit.MINUTES); // Timeout of 10 minutes. 
executor.shutdown(); 

여기 TaskRunnable을 구현합니다.

+0

좋은 제안이지만 ExecutorService가 차단 된 경우에도 스레드를 시간 초과 할 수 있습니까? – Traker

+1

스레드가 중단됩니다. Javadoc을 소개하고 싶다면'ExecutorService # awaitTermination()'을 사용하면된다. – BalusC

+14

IMHO,'invokeAll'은 과잉입니다. 'executor.submit (new Task()). get (10, TimeUnit.MINUTES); ' –

5

왜 특정 시간 이후에 interrupt()이 표시되지 않습니까? 스폰 된 스레드는 InterruptedException을 제대로 처리 할 수 ​​있어야합니다.

스레드를 완전히 종료하는 방법에 대한 자세한 내용은이 문서 (http://www.javaspecialists.eu/archive/Issue056.html)를 참조하십시오.

특정 시간 제한 내에서 결과를 수집하고 스레드를 종료하는 유용한 방법을 제공하는 Executor/Future 프레임 워크를 참조하십시오.

+1

쓰래드가 던져 질 수있는 호출을하면 쓰레드는'InterruptedException'에 응답하면됩니다. 루프 내에서 돌고있는 경우는,'Thread.isInterrupted()'(또는 단지'Thread.interrupted()', 현재의 thread를 의미)를 사용해, 인터럽트 플래그를 체크 할 필요가 있습니다. –

0

스레드를 죽이는 것은 일반적으로 Thread의 API 문서와 연결된 이유 때문에 좋지 않습니다.

살인시에 죽었 으면 완전히 새로운 과정을 사용하십시오.

그렇지 않으면 일반적인 질문은 스레드 폴 System.nanoTime, 폴링 (가능하면 volatile) 플래그, 대기열 "독약"또는 그와 유사한 것입니다.

+0

이 스레드가 실행되는 코드를 소유하고 있지 않은 상태에서 죽었는지 확인해야 할 경우 스레드를 죽이는 것이 중요 할 수 있습니다. 두 코드를 동일한 가상 주소에서 실행해야하는 경우가 있습니다. –

+0

@Elazar 프로세스가 안정적으로 유지되는 것이 거의 확실합니다. –

0

Brian의 말처럼 스레드를 "중지하는 것"보다 방해가되지 않습니다.
스레드가 중간 수정 객체에서 잠겨 있고 갑자기 중지되면 (잠금이 해제됩니다) 어떻게됩니까? 이상한 결과가납니다.

4

직접적으로; 가장 간단한 방법은 해당 시간 제한이있는 해당 스레드에 조인()하고 조인이 종료 될 때까지 스레드가 인터럽트되지 않으면 인터럽트하는 것입니다. 그래서

, 내가 대신 실제로 살인의 인터럽트를 사용

Thread t = ... 
t.join(timelimit); 
if (t.isAlive) t.interrupt(); 

주의, 그것은 훨씬 더 안전합니다. 또한 직접 스레드를 조작하는 대신 실행 프로그램을 사용하는 것이 좋습니다.

+0

다른 스레드가 모든 CPU를 점유하면 너무 큰 지연 후에 조인이 _started_됩니다. – mafu

+0

나는'if (t.isAlive())'를 읽어야한다고 생각한다. – PHPirate

0

아무런 정리 작업을 수행하지 않으므로 destroy()을 사용하지 마십시오.

가장 간단한 방법은 당신이 ExecutorService을 사용할 수

try { 
    thread.join(); 
} catch (InterruptedException e) {//log exception...} 

처럼 join()을 사용하는 것입니다. 여러 스레드가 동시에 실행되는 경우 이는 많은 의미가 있습니다. 다른 스레드가 실행되는 동안 새 스레드를 생성해야하는 경우이를 BlockingQueue과 결합 할 수 있습니다.

ThreadPoolExecutor (ExecutorService -implementation)은 인수로 BlockingQueue을 사용할 수 있으며 새 스레드를 큐에 추가하기 만하면됩니다. 완료되면 ThreadPoolExecutor을 종료하면됩니다.

private BlockingQueue<Runnable> queue; 
... 
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, new Long(1000), 
       TimeUnit.MILLISECONDS, this.queue); 

대기열에 추가 된 모든 스레드 수를 유지할 수 있습니다. 작업이 완료되었다고 생각하면 대기열이 비어 있습니다 (아마도 대기열이 비어 있습니다).

if (issuedThreads == pool.getCompletedTaskCount()) { 
     pool.shutdown(); 
    } 

두 개가 일치하면 작업이 완료된 것입니다. (I 개발자를 해요) jcabi-aspects에서 방법

try { 
     while (!this.pool.awaitTermination(1000, TimeUnit.MILLISECONDS)); 
} catch (InterruptedException e) {//log exception...} 
1

당신은 AOP를 사용할 수 있으며, @Timeable 주석 : 풀을 종료하는 또 다른 방법은 루프에 두 번째를 기다리는

@Timeable(limit = 1, unit = TimeUnit.SECONDS) 
String load(String resource) { 
    // do something time consuming 
} 

시간 제한에 도달하면 스레드는 interrupted() 플래그를 true으로 설정하고이 상황을 올바르게 처리하고 실행을 중지하는 것이 좋습니다. 일반적으로 완료는 Thread.sleep(..)입니다.

CompletableFuture.runAsync(thread::run) 
    .orTimeout(30, TimeUnit.SECONDS) 
    .exceptionally(throwable -> { 
     log.error("An error occurred", throwable); 
     return null; 
    }); 

자바 8에서, 불행하게도, 당신은 사용해야합니다

0

도움이되는 몇 가지 변화가 지금은 orTimeout 방법을 사용하여 자바 9. 이후 CompletableFutureJEP 266의 일환으로 도입, 좋아 작성할 수 있습니다 약간의 여분의 코드. 여기에 Lombok의 도움으로 위임 패턴 사용의 예입니다

import com.google.common.util.concurrent.ThreadFactoryBuilder; 
import java.time.Duration; 
import java.util.concurrent.CompletableFuture; 
import java.util.concurrent.Executors; 
import static java.util.concurrent.TimeUnit.MILLISECONDS; 
import java.util.concurrent.TimeoutException; 
import static lombok.AccessLevel.PRIVATE; 
import lombok.AllArgsConstructor; 
import lombok.experimental.Delegate; 

@AllArgsConstructor(access = PRIVATE) 
public class TimeoutableCompletableFuture<T> extends CompletableFuture<T> { 

    public static TimeoutableCompletableFuture<Void> runAsync(
      Runnable runnable) { 
     return new TimeoutableCompletableFuture<>(
       CompletableFuture.runAsync(runnable)); 
    } 

    @Delegate 
    private final CompletableFuture<T> baseFuture; 

    public TimeoutableCompletableFuture<T> orTimeout(Duration duration) { 
     final CompletableFuture<T> otherFuture = new CompletableFuture<>(); 
     Executors.newScheduledThreadPool(
       1, 
       new ThreadFactoryBuilder() 
       .setDaemon(true) 
       .setNameFormat("timeoutable-%d") 
       .build()) 
       .schedule(() -> { 
        TimeoutException ex = new TimeoutException(
          "Timeout after " + duration); 
        return otherFuture.completeExceptionally(ex); 
       }, duration.toMillis(), MILLISECONDS); 

     return new TimeoutableCompletableFuture<>(
       baseFuture.applyToEither(otherFuture, a -> a)); 
    } 
} 

물론, 위의 코드는 쉽게 단지 정적 팩토리 메소드로 다시 작성할 수 있습니다 : 당신이 기다릴 사용하고있는

public static CompletableFuture<Void> runAsyncOrTimeout(
     Runnable runnable, long timeout, TimeUnit unit) { 

    CompletableFuture<Void> other = new CompletableFuture<>(); 
    Executors.newScheduledThreadPool(
      1, 
      new ThreadFactoryBuilder() 
      .setDaemon(true) 
      .setNameFormat("timeoutafter-%d") 
      .build()) 
      .schedule(() -> { 
       TimeoutException ex = new TimeoutException(
         "Timeout after " + timeout); 
       return other.completeExceptionally(ex); 
      }, timeout, unit); 
    return CompletableFuture.runAsync(runnable).applyToEither(other, a -> a); 
} 
관련 문제