FutureTask的cancel方法真的能终止正在运行的线程吗?

FutureTask的cancel方法真的能终止正在运行的线程吗?_第1张图片
Future的API

【疑问】

Future有一个cancel(mayInterruptIfRunning)方法。mayInterruptIfRunning代表什么意思呢?它的值会影响任务的中断吗?

【分析】

1. FutureTask中线程的运行状态

    /*
     * Possible state transitions:
     * NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;

下图是线程的生命周期,可以看到和代码中的状态不是一回事情。

FutureTask的cancel方法真的能终止正在运行的线程吗?_第2张图片
图1-线程的声明周期.png

FutureTask的生命周期是怎样的呢,它和线程的生命周期有没有共通之处呢?

FutureTask的cancel方法真的能终止正在运行的线程吗?_第3张图片
图2-FutureTask生命周期.png
  • New状态:线程生命周期的New状态,Runnable状态,blocked状态;
  • Completing状态:线程生命周期的Running状态;
  • normal、exceptional、cancelled、interrupted状态:线程生命周期的Terminated状态;

使用FutureTask执行Task()线程逻辑:

    //创建FutureTask实例
    FutureTask futureTask = new FutureTask(new Task());
    //执行FutureTask
    new Thread(futureTask).start();

2. 线程的中断方法

  1. FutureTask不为New状态,那么直接返回false。

  2. 若status状态为New。
    2.1参数mayInterruptIfRunning=false,任务不会被中断,并且任务的状态为cancelled(FutureTask的终态)。
    2.2 参数mayInterruptIfRunning=true,status状态会变为interrupting,FutrueTask中的线程会调用interrupt()方法,(若线程为Running状态,则会变更isInterrupted标志位。若线程为Blocking状态,则会抛出异常,终止线程)。接着会变更为interrupted(FutureTask的终态)。

源码:java.util.concurrent.FutureTask#cancel

   public boolean cancel(boolean mayInterruptIfRunning) {
      // 1. 判断
        if (!(state == NEW &&
              UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
            return false;
        try {    // in case call to interrupt throws exception
            if (mayInterruptIfRunning) {
                try {
                    //调用Thread
                    Thread t = runner;
                    if (t != null)
                        t.interrupt();
                } finally { // final state
                    UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
                }
            }
        } finally {
            finishCompletion();
        }
        return true;
    }

以线程角度考虑:

  1. 线程为New状态时调用cancel方法,无论参数如何FutureTask的status均是终态。故即使调用线程的start方法,线程也不会执行,故为中断。

  2. 线程为Runnable或blocking状态时,cancel参数为true时便可执行thread的interrupt方法。线程会捕获中断异常,进而结束线程。

  3. 线程为running状态时,FutureTask为completing状态。interrupt无法中断正在持有cpu资源的线程,故方法直接返回false。

附录

 UNSAFE.compareAndSwapInt(this, valueOffset, expect,update)

CAS的比较算法,原理就是通过比较预期值expect和主存中的valueOffset是否相等,若不相等返回false,若相等,则使用update更新主存中的valueOffset值。

UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);

interrupted状态刷新到主存中。

推荐阅读

  1. 源码导读-帮助篇-什么叫做CAS算法【图文版】
  2. 小小建议——多线程与并发(1)线程的创建和使用

你可能感兴趣的:(FutureTask的cancel方法真的能终止正在运行的线程吗?)