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

时间:2022-09-25 21:01:49

Is there a way to kill a child thread after some specified time limit in Java? Edit: Also this particular thread may be blocked in its worst case (Thread is used to wait for a file modification and blocks until this event occurs), so im not sure that interrupt() will be successful?

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

8 个解决方案

#1


35  

Make use of ExecutorService to execute the Runnable, checkout the methods wherein you can specify the timeout. E.g.

使用ExecutorService执行Runnable,检查可以指定超时的方法。例如。

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

Here Task of course implements Runnable.

这里的Task当然实现了Runnable。

#2


5  

Why not interrupt() it after a particular time ? Your spawned thread will have to be able to handle an InterruptedException properly.

为什么不在特定时间后中断()它?您生成的线程必须能够正确处理InterruptedException。

See this article (http://www.javaspecialists.eu/archive/Issue056.html) for more information on shutting down threads cleanly.

有关干净地关闭线程的更多信息,请参阅此文章(http://www.javaspecialists.eu/archive/Issue056.html)。

See also the Executor/Future framework, which provide useful methods for collecting results and/or terminating threads within particular time limits.

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

#3


4  

Not directly; I think the simplest way is to join() on that thread with that time limit, and interrupt the thread if it's not done by the time the join ended.

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

So,

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

Notice I used interrupt instead of actually killing it, it's much safer. I would also recommend using executors instead of directly manipulating threads.

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

#4


2  

Some helpful changes were introduced as part of JEP 266 in CompletableFuture since Java 9. Using orTimeout method, for now, it is possible to write it like:

自Java 9以来,在CompletableFuture中作为JEP 266的一部分引入了一些有用的更改。使用orTimeout方法,现在可以像下面这样编写它:

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

In Java 8, unfortunately, you should use some extra code. Here is an example of delegation pattern usage with help of Lombok:

不幸的是,在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));
    }
}

Of course, the code above easily could be rewritten as just a static factory method:

当然,上面的代码很容易被重写为一个静态的工厂方法:

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


1  

You can use AOP and a @Timeable annotation for your method from jcabi-aspects (I'm a developer):

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

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

When time limit is reached your thread will get interrupted() flag set to true and it's your job to handle this situation correctly and to stop execution. Normally it's done by Thread.sleep(..).

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

#6


0  

Killing a thread is generally a bad idea for reasons linked to for the API docs for Thread.

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

If you are dead set on killing, use a whole new process.

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

Otherwise the usual thing is to have the thread poll System.nanoTime, poll a (possible volatile) flag, queue a "poison pill" or something of that nature.

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

#7


0  

Brian's right, interrupting it is safer than "stopping" the thread.
What if the thread is locking on an object mid-modification, and suddenly gets stopped (which causes the lock to be released)? You get weird results.

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

#8


0  

Do not use destroy() since that does not perform any cleanup.

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

The most straightforward way is to use join(), like

最直接的方法是使用join(),就像

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

You could use an ExecutorService. That would make a lot of sense if you have several threads running concurrently. If you have the need to spawn new threads while other threads are running, you can combine this with a BlockingQueue.

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

A ThreadPoolExecutor (an ExecutorService-implementation) can take a BlockingQueue as argument, and you can simply add new threads to the queue. When you are done you simply terminate the ThreadPoolExecutor.

ThreadPoolExecutor(ExecutorService实现)可以将BlockingQueue作为参数,您只需将新线程添加到队列中即可。完成后,您只需终止ThreadPoolExecutor即可。

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

You can keep a count of all the threads added to the queue. When you think you are done (the queue is empty, perhaps?) simply compare this to

您可以保留添加到队列中的所有线程的计数。当你认为你已经完成时(队列是空的,也许?)只需将其与之比较即可

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

If the two match, you are done. Another way to terminate the pool is to wait a second in a loop:

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

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

#1


35  

Make use of ExecutorService to execute the Runnable, checkout the methods wherein you can specify the timeout. E.g.

使用ExecutorService执行Runnable,检查可以指定超时的方法。例如。

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

Here Task of course implements Runnable.

这里的Task当然实现了Runnable。

#2


5  

Why not interrupt() it after a particular time ? Your spawned thread will have to be able to handle an InterruptedException properly.

为什么不在特定时间后中断()它?您生成的线程必须能够正确处理InterruptedException。

See this article (http://www.javaspecialists.eu/archive/Issue056.html) for more information on shutting down threads cleanly.

有关干净地关闭线程的更多信息,请参阅此文章(http://www.javaspecialists.eu/archive/Issue056.html)。

See also the Executor/Future framework, which provide useful methods for collecting results and/or terminating threads within particular time limits.

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

#3


4  

Not directly; I think the simplest way is to join() on that thread with that time limit, and interrupt the thread if it's not done by the time the join ended.

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

So,

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

Notice I used interrupt instead of actually killing it, it's much safer. I would also recommend using executors instead of directly manipulating threads.

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

#4


2  

Some helpful changes were introduced as part of JEP 266 in CompletableFuture since Java 9. Using orTimeout method, for now, it is possible to write it like:

自Java 9以来,在CompletableFuture中作为JEP 266的一部分引入了一些有用的更改。使用orTimeout方法,现在可以像下面这样编写它:

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

In Java 8, unfortunately, you should use some extra code. Here is an example of delegation pattern usage with help of Lombok:

不幸的是,在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));
    }
}

Of course, the code above easily could be rewritten as just a static factory method:

当然,上面的代码很容易被重写为一个静态的工厂方法:

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


1  

You can use AOP and a @Timeable annotation for your method from jcabi-aspects (I'm a developer):

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

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

When time limit is reached your thread will get interrupted() flag set to true and it's your job to handle this situation correctly and to stop execution. Normally it's done by Thread.sleep(..).

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

#6


0  

Killing a thread is generally a bad idea for reasons linked to for the API docs for Thread.

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

If you are dead set on killing, use a whole new process.

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

Otherwise the usual thing is to have the thread poll System.nanoTime, poll a (possible volatile) flag, queue a "poison pill" or something of that nature.

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

#7


0  

Brian's right, interrupting it is safer than "stopping" the thread.
What if the thread is locking on an object mid-modification, and suddenly gets stopped (which causes the lock to be released)? You get weird results.

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

#8


0  

Do not use destroy() since that does not perform any cleanup.

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

The most straightforward way is to use join(), like

最直接的方法是使用join(),就像

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

You could use an ExecutorService. That would make a lot of sense if you have several threads running concurrently. If you have the need to spawn new threads while other threads are running, you can combine this with a BlockingQueue.

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

A ThreadPoolExecutor (an ExecutorService-implementation) can take a BlockingQueue as argument, and you can simply add new threads to the queue. When you are done you simply terminate the ThreadPoolExecutor.

ThreadPoolExecutor(ExecutorService实现)可以将BlockingQueue作为参数,您只需将新线程添加到队列中即可。完成后,您只需终止ThreadPoolExecutor即可。

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

You can keep a count of all the threads added to the queue. When you think you are done (the queue is empty, perhaps?) simply compare this to

您可以保留添加到队列中的所有线程的计数。当你认为你已经完成时(队列是空的,也许?)只需将其与之比较即可

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

If the two match, you are done. Another way to terminate the pool is to wait a second in a loop:

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

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