1. interrupt知识点

PS: 以下总结基于JDK8

本文不会完整说明interrupt,只会罗列一些比较重要的点。完整了解Thread.interrupt可以看参考资料。

以下的一些理解新的有助于理解参考资料的文章:

  1. interrupt方法调用后,针对BLOCKED状态的线程,只是设定中断标志位为true。是否响应中断(感知这个标志位的变化)取决于API的设计。JDK的阻塞IO API、Synchronized同步块、还有Lock中的很多方法(不包括lockInterruptibly)都是不响应中断的。当然调用线程可以利用标志位判断来使得自己设计的API是可响应中断的。
  2. interrupt方法调用后,针对WAITING/TIMED_WAITING状态的线程,会上抛interruptedException**并且设置中断标志位false**。例如线程调用Thread.sleep,Object.wait()之后。
  3. 如果线程尚未启动(NEW),或者已经结束(TERMINATED),则调用interrupt()对它没有任何效果,中断标志位也不会被设置。
  4. 最佳实践:有时候一些方法设计上不允许被中断或者取消,但是当别的线程发来中断请求的时候,也需要进行标记的保留,方便其他调用方“了解情况”
public Task getNextTask(BlockingQueue<Task> queue) {
    boolean interrupted = false;
    try {
        while (true) {
            try {
                return queue.take();
            } catch (InterruptedException e) {
                //fianlly中依赖的状态标记
                interrupted = true;
                // fall through and retry
            }
        }
    } finally {
        if (interrupted)
        //在fianlly中重新标记,确保没有丢失中断通知
            Thread.currentThread().interrupt();
    }
}
  1. 利用中断可以实现一些cancel的操作。例如:
package concurrent;


import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by wanshao
 * Date: 2017/12/18
 * Time: 下午3:42
 **/
public class InterruptExample {
    public static void main(String[] args) throws InterruptedException {
        InterruptTask interruptTask = new InterruptTask();
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(interruptTask);
        Thread.sleep(100);
        interruptTask.cancel();
        executorService.shutdown();

    }
}

/**
 * 一个响应中断的任务
 */
class InterruptTask implements Callable<Integer> {
    private BlockingQueue<Task> queue;
    //保存要被interrupt的线程
    Thread t;

    @Override
    public Integer call() throws InterruptedException {
        System.out.println("start a blocked task");
        try {
            t = Thread.currentThread();
            Thread.currentThread().sleep(50000);
        } catch (InterruptedException e) {
            System.out.println("be interrupted");
            e.printStackTrace();
        }

        return 0;
    }

    public void cancel() {
        System.out.println("cacel a task....");
        //这里直接调用Thread.currentThread()会获取到main线程,而不是线程池里面的线程

        if (!t.isInterrupted()) {
            t.interrupt();
        }
    }
}

2. 参考资料

Handling InterruptedException in Java
处理 InterruptedException
https://zhuanlan.zhihu.com/p/27857336