涉及概念:
- 线程池:使用
ExecutorService
或ScheduledExecutorService
来管理线程,避免手动创建和管理线程。 - Future 和 CompletableFuture:用于获取异步任务的结果或处理异步任务的完成。
- 优雅关闭:确保在应用程序关闭时能够正确关闭线程池和取消未完成的任务。
示例:
ScheduledExecutorService
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class PerpetualAsyncTask {
private final ScheduledExecutorService executorService;
private final ScheduledFuture<?> scheduledFuture;
public PerpetualAsyncTask() {
// 创建一个单线程的ScheduledExecutorService
executorService = Executors.newSingleThreadScheduledExecutor();
// 提交一个永动任务
Runnable task = () -> {
// 这里是你的任务逻辑
System.out.println("Task is running...");
};
// 初始延迟为0,然后每隔1秒执行一次任务
scheduledFuture = executorService.scheduleAtFixedRate(task, 0, 1, TimeUnit.SECONDS);
}
// 优雅关闭的方法
public void shutdown() {
// 取消任务
scheduledFuture.cancel(true);
// 关闭线程池
executorService.shutdown();
try {
// 等待线程池中的所有任务都执行完毕或超时
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
// 强制关闭线程池,可能会导致正在执行的任务被中断
executorService.shutdownNow();
}
} catch (InterruptedException e) {
// 如果在等待过程中被中断,则也强制关闭线程池
executorService.shutdownNow();
Thread.currentThread().interrupt(); // 保留中断状态
}
}
public static void main(String[] args) throws InterruptedException {
PerpetualAsyncTask task = new PerpetualAsyncTask();
// 模拟应用程序运行一段时间
Thread.sleep(10000); // 等待10秒
// 关闭永动任务
task.shutdown();
}
}
在这个示例中,我们创建了一个PerpetualAsyncTask
类,它使用ScheduledExecutorService
来提交一个永动任务。我们还提供了一个shutdown
方法,用于优雅地关闭线程池和取消任务。
在main
方法中,我们创建了一个PerpetualAsyncTask
实例,并让它运行一段时间(这里模拟为10秒)。然后,我们调用shutdown
方法来关闭永动任务。
注意以下几点:
ScheduledFuture.cancel(true)
用于尝试取消任务。如果任务已经开始执行,则取消可能不会立即生效。executorService.shutdown()
开始关闭线程池,不再接受新任务,但会等待已提交的任务执行完毕。executorService.awaitTermination
用于等待线程池中的任务执行完毕或超时。- 如果在等待过程中线程被中断,或者超时后仍有任务未执行完毕,我们使用
executorService.shutdownNow()
来强制关闭线程池,这可能会导致正在执行的任务被中断。
ExecutorService
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PerpetualExecutorAsyncTask {
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
// 提交一个永动任务
executorService.submit(() -> {
while (true) {
// 执行你的任务逻辑
System.out.println("永动任务正在运行...");
// 可以根据需要添加休眠来减少CPU占用
try {
Thread.sleep(1000); // 每秒执行一次
} catch (InterruptedException e) {
// 如果线程被中断,可以选择退出循环或重新设置中断状态
Thread.currentThread().interrupt();
break;
}
}
});
// 主线程可以继续执行其他任务,或者可以选择等待所有任务完成
// 例如,通过调用 executorService.shutdown() 和 executorService.awaitTermination()
// 注意:不要在这里关闭executorService,否则永动任务会被中断
}
// 当程序结束时,确保优雅地关闭ExecutorService
public static void shutdown() {
executorService.shutdown(); // 不接受新任务
try {
// 等待所有任务完成,或者超时后退出
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow(); // 取消所有正在执行的任务并停止处理正在等待的任务
}
} catch (InterruptedException ie) {
// 如果在等待过程中被中断,则重新设置中断状态并停止ExecutorService
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
在这个例子中,我们创建了一个单线程的ExecutorService
,并提交了一个永动任务。任务是一个无限循环,每次循环执行一些逻辑(在这个例子中只是打印一条消息),然后休眠一秒。
请注意,长时间运行的永动任务可能会消耗大量的系统资源,因此通常会在任务中添加一些休眠逻辑,以减少CPU的占用。此外,为了优雅地关闭ExecutorService
,我们提供了一个shutdown
方法,它首先尝试正常关闭(不再接受新任务,并等待现有任务完成),如果超时则尝试强制关闭(取消所有任务)。
在真实场景中,你可能还需要考虑如何优雅地处理任务的中断,例如在任务中捕获InterruptedException
,并决定是重新设定中断状态并退出循环,还是只是重置中断状态并继续执行。
最后,确保在应用程序结束前调用shutdown
方法来清理资源,避免资源泄露。