在Java中指定一些时间限制后杀死线程

时间:2010-04-28 21:47:34

标签: java multithreading

有没有办法在Java中指定的时间限制后终止子线程? 编辑:此特定线程也可能在最坏的情况下被阻止(线程用于等待文件修改并阻塞直到发生此事件),所以我不确定interrupt()是否会成功?

8 个答案:

答案 0 :(得分:36)

利用ExecutorService执行Callable,检查可以指定超时的方法。 E.g。

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

此处Task当然会实现Callable

答案 1 :(得分:5)

为什么不在特定时间之后interrupt()呢?您的衍生线程必须能够正确处理InterruptedException

有关彻底关闭线程的详细信息,请参阅此文章(http://www.javaspecialists.eu/archive/Issue056.html)。

另请参阅Executor / Future框架,它提供了在特定时间限制内收集结果和/或终止线程的有用方法。

答案 2 :(得分:4)

不直接;我认为最简单的方法是使用该时间限制在该线程上加入(),如果在连接结束时没有完成,则中断该线程。

所以,

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

注意我使用了中断而不是实际杀死它,它更安全。我还建议使用执行程序而不是直接操作线程。

答案 3 :(得分:2)

您可以从@Timeable(我是开发人员)为您的方法使用AOP和jcabi-aspects注释:

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

当达到时间限制时,您的线程将interrupted()标志设置为true,您的工作就是正确处理这种情况并停止执行。通常由Thread.sleep(..)完成。

答案 4 :(得分:2)

自Java 9以来,CompletableFutureJEP 266的一部分引入了一些有用的更改。使用orTimeout方法,现在可以将它写成:

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

不幸的是,在Java 8中,您应该使用一些额外的代码。以下是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);
}

答案 5 :(得分:0)

对于与Thread的API文档相关联的原因,杀死某个帖子通常是一个坏主意。

如果你死定了,请使用一个全新的过程。

否则通常的做法是让线程轮询System.nanoTime,轮询一个(可能的volatile)标志,排队“毒丸”或那种性质的东西。

答案 6 :(得分:0)

Brian是对的,打断它比“停止”线程更安全 如果线程在中间修改时锁定对象并突然停止(导致锁被释放)怎么办?你得到了奇怪的结果。

答案 7 :(得分:0)

不要使用destroy(),因为它不会执行任何清理。

最直接的方法是使用join(),例如

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

您可以使用ExecutorService。如果你有几个并发运行的线程,这将是很有意义的。如果您需要在其他线程运行时生成新线程,则可以将其与BlockingQueue结合使用。

ThreadPoolExecutorExecutorService - 实现)可以将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();
    }

如果两者匹配,你就完成了。终止池的另一种方法是在循环中等待一秒:

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