zl程序教程

您现在的位置是:首页 >  大数据

当前栏目

并发编程7 - 任务取消

并发编程 任务 取消
2023-09-14 08:58:00 时间

3. 分解任务其中一条发现了解决方案,其他的就可以取消了

4. 分解任务其中一条发现了对于其他任务都有影响的错误,比如磁盘空间已满,其他的可以取消了

5. 关闭,  当执行器关闭的时候,必须对正在处理及等待处理的任务进行优雅的关闭。


一个最简单的方式是,加上取消标记,cancel方法设置取消标记。 主流程中判断取消标记,进行操作

public class TestCallable {

 public static void main(String[] args) {

 ThreadTest thread = new ThreadTest();

 thread.start();

 thread.cancel();

class ThreadTest extends Thread{

 private boolean cancel = false;

 @Override

 public void run() {

 while(!cancel){

 doSomething();

 System.out.println("被取消了");

 private void doSomething() {

 // ...

 public void cancel(){

 this.cancel = true;

}
这样有个问题,如果doSomthing()的时候有阻塞,就永远不会监测到cancel的状态,  在JDK中我们还能使用专门为了取消而存在的中断方法。


上面的代码就会改为这样:

public class TestCallable {

 public static void main(String[] args) {

 ThreadTest thread = new ThreadTest();

 thread.start();

 thread.cancel();

class ThreadTest extends Thread {

 @Override

 public void run() {

 try {

 while (!Thread.currentThread().isInterrupted()) {

 doSomething();

 } catch (InterruptedException e) {

 e.printStackTrace();

 System.out.println("被取消了");

 private void doSomething() throws InterruptedException {

 // ...

 TimeUnit.SECONDS.sleep(1000);

 public void cancel() {

 interrupt();

}
这里再来看一个用法,使用超时加上中断来决定任务执行多久:

public static void main(String[] args) {

 ScheduledExecutorService service = Executors.newScheduledThreadPool(1);

 final ThreadTest thread = new ThreadTest();

 service.schedule(new Runnable() {

 @Override

 public void run() {

 thread.cancel();

 }, 1, TimeUnit.SECONDS);

 thread.start();

 }

给线程加中断有一个原则就是一定要清楚中断策略,否则就不要使用中断方法。


使用Future完成取消

例如:

public class TestCallable {

 public static void main(String[] args) {

 ExecutorService service = Executors.newFixedThreadPool(1);

 ThreadTest thread = new ThreadTest();

 Future f = service.submit(thread);

 Future f2 = service.submit(new ThreadTest());

 try {

 f.get(1, TimeUnit.SECONDS);

 } catch (InterruptedException e) {

 e.printStackTrace();

 } catch (ExecutionException e) {

 e.printStackTrace();

 } catch (TimeoutException e) {

 e.printStackTrace();

 f.cancel(true);

 f2.cancel(false);

class ThreadTest extends Thread {

 @Override

 public void run() {

 System.out.println("开始运行1");

 try {

 TimeUnit.SECONDS.sleep(3);

 } catch (InterruptedException e) {

 e.printStackTrace();

 System.out.println("执行完成1");

}
其中断策略为:

.cancel(true),表示如果运行尝试对当前线程进行中断,一般是调用当前线程的.interrupt()方法

.cancel(false),表示如果没运行则不会运行这个线程了,如果运行了,会等到运行完成。

停止基于线程的服务

比如生产者消费者模式。

因为其使用了take()阻塞的方法,能够响应中断,所以如果生产者阻塞了不是问题,但是这样中断可能不太好。

我们可以加入状态标志,当设置了关闭标志之后,再生产就会抛出异常,  这个跟Executor的shutdown方法是一样的。

还有一种方式是使用致命药丸,就是在队列中加入一个特殊的任务,执行到这个药丸就停止服务。

使用TrackingExecutor类还能够获取已经取消了的任务, 用exec.getCancelledTasks()来获取


任务中的异常处理

在Executors.newFixedThreadPool(int , ThreadFactory threadFactory)中的第二个构造参数,是当一个线程异常中断的时候从这个factory中创建新的线程补充进去,可以用来做异常处理

或者一般情况下,使用Future.get方法可以得到异常


JVM关闭

正常关闭,System.exit()可以注册关闭钩子如下:

public class TestCallable {

 public static void main(String[] args) {

 Runtime.getRuntime().addShutdownHook(new Thread(){

 @Override

 public void run() {

 System.out.println("运行于JVM退出之前");

 System.exit(0);

}


daemon的线程,不会影响线程的退出。不会执行finally块,通常用于内部的事务处理。


避免使用Finalizer.不提供任何保证,并且会带来巨大的性能开销。


Java并发编程实战(线程控制操作详解) 在使用Java实际编程中,多线程可以说是无所不在,凡是需要并发执行的都可以用到它,一个应用程序中不用多线程将会是很糟糕的事情,所以掌握线程以及它的控制操作是非常重要的。
java并发多线程显式锁Condition条件简介分析与监视器 多线程下篇(四) java并发多线程显式锁Condition条件简介分析与监视器 多线程下篇(四) Lock接口提供了方法Condition newCondition();用于获取对应锁的条件,可以在这个条件对象上调用监视器方法 可以理解为,原本借助于synchronized关键字以及锁对象,配备了一个监视器
JAVA媒体提供任务机制来安全的终止线程。但是它提供了中断(interruption),这是一种写作机制,能够使一个线程终止另外一个线程。 一般来说没人希望立即终止,因为必要时总要先清理再终止。