任务终止的最佳实践

Posted 公众号JavaEdge

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了任务终止的最佳实践相关的知识,希望对你有一定的参考价值。

设置任务周期性检查的标志,然后任务就能通过自己的shutdown进程并正常终止。不是在任务中随机关闭线程,而是要求任务在到达一个较好时机自行终止。这总能产生比中断更好的结果以及更易理解、更合理的代码。
以这种方式终止任务听起来很简单:设置任务可以看到的boolean flag。编写任务,以便定期检查标志并执行正常终止。这实际上就是你所做的,但有个问题:我们的旧克星,共同的可变状态。若该标志能被另一个任务操纵,则存在碰撞的可能性。

对此,你也知道很多解决这个问题的方法,比如使用volatile。本文将使用更简单的技术并避免所有易变参数。

Java 5引入Atomic类,提供了一组可以使用的类型,而不必担心并发问题。

添加AtomicBoolean标志,告诉任务清理自己并退出。


// concurrent/QuittableTask.java
import java.util.concurrent.atomic.AtomicBoolean;import onjava.Nap;
public class QuittableTask implements Runnable
final int id;
public QuittableTask(int id)
this.id = id;

private AtomicBoolean running =
new AtomicBoolean(true);
public void quit()
running.set(false);

@Override
public void run()
while(running.get()) // [1]
new Nap(0.1);
System.out.print(id + " "); // [2]


虽然多个任务可以在同一个实例上成功调用quit(),但是AtomicBoolean可以防止多个任务同时实际修改running,从而使quit()方法成为线程安全的。


  • [1]:只要运行标志为true,此任务的run()方法将继续。
  • [2]: 显示仅在任务退出时发生。

需要running AtomicBoolean证明编写Java program并发时最基本的困难之一是,如果running是一个普通的布尔值,你可能无法在执行程序中看到问题。实际上,在这个例子中,你可能永远不会有任何问题 - 但是代码仍然是不安全的。编写表明该问题的测试可能很困难或不可能。因此,你没有任何反馈来告诉你已经做错了。通常,你编写线程安全代码的唯一方法就是通过了解事情可能出错的所有细微之处。

作为测试,我们将启动很多QuittableTasks然后关闭它们。尝试使用较大的COUNT值

// concurrent/QuittingTasks.java
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
import onjava.Nap;
public class QuittingTasks
public static final int COUNT = 150;
public static void main(String[] args)
ExecutorService es =
Executors.newCachedThreadPool();
List<QuittableTask> tasks =
IntStream.range(1, COUNT)
.mapToObj(QuittableTask::new)
.peek(qt -> es.execute(qt))
.collect(Collectors.toList());
new Nap(1);
tasks.forEach(QuittableTask::quit); es.shutdown();

输出结果:

24 27 31 8 11 7 19 12 16 4 23 3 28 32 15 20 63 60 68 6764 39 47 52 51 55 40 43 48 59 44 56 36 35 71 72 83 10396 92 88 99 100 87 91 79 75 84 76 115 108 112 104 107111 95 80 147 120 127 119 123 144 143 116 132 124 128
136 131 135 139 148 140 2 126 6 5 1 18 129 17 14 13 2122 9 10 30 33 58 37 125 26 34 133 145 78 137 141 138 6274 142 86 65 73 146 70 42 149 121 110 134 105 82 117106 113 122 45 114 118 38 50 29 90 101 89 57 53 94 4161 66 130 69 77 81 85 93 25 102 54 109 98 49 46 97

我使用peek()QuittableTasks传递给ExecutorService,然后将这些任务收集到List.main()中,只要任何任务仍在运行,就会阻止程序退出。即使为每个任务按顺序调用quit()方法,任务也不会按照它们创建的顺序关闭。独立运行的任务不会确定性地响应信号。

以上是关于任务终止的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

AWS EC2-Instance 备份/终止/启动的最佳实践是啥

后端日志最佳实践

在 C 中等待子进程终止的最佳实践

更新 AWS ECS 服务任务的最佳实践

Android 计划后台任务的最佳实践

AWS 任务角色策略的最佳实践