• 线程中断总结


    在Java中,停止一个线程的主要机制是中断,中断并不是强迫终止一个线程,它是一种协作机制,是给线程传递一个取消信号,但是由线程来决定如何以及何时退出。

    Thread类定义了如下方法:

    public boolean isInterrupted();//测试此线程是否已被中断。此方法不影响线程的中断状态
    public void interrupt();//中断线程
    public static boolean interrupted();//测试此线程是否已被中断,并清空中断标志位

    interrupt()对线程的影响与线程的状态和在进行的IO操作有关,我们先考虑线程的状态:

    • RUNNABLE:线程在运行或具备运行条件只是在等待操作系统调度
    • WAITING/TIMED_WAITING:线程在等待某个条件或超时
    • BLOCKED:线程在等待锁,试图进入同步块
    • NEW / TERMINATED:线程还未启动或已结束

    RUNNABLE

    如果线程在运行中,且没有执行IO操作,interrupt()只是会设置线程的中断标志位,没有任何其它作用。线程应该在运行过程中合适的位置检查中断标志位,如:

    public class InterruptRunnableDemo extends Thread {
        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                // ... 单次循环代码
            }
            System.out.println("done ");
        }
    
        public static void main(String[] args) throws InterruptedException {
            Thread thread = new InterruptRunnableDemo();
            thread.start();
            Thread.sleep(1000);
            thread.interrupt();
        }
    }

    WAITING/TIMED_WAITING

    线程执行如下方法会进入WAITING状态:

    public final void join() throws InterruptedException
    public final void wait() throws InterruptedException

    执行如下方法会进入TIMED_WAITING状态:

    public final native void wait(long timeout) throws InterruptedException;
    public static native void sleep(long millis) throws InterruptedException;
    public final synchronized void join(long millis) throws InterruptedException

    在这些状态时,对线程对象调用interrupt()会使得该线程抛出InterruptedException,需要注意的是,抛出异常后,中断标志位会被清空,而不是被设置。比如:

      public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
          @Override
          public void run() {
            try {
              Thread.sleep(1000);
            } catch (InterruptedException e) {
              System.out.println(isInterrupted());
            }
          }
        };
        t.start();
        try {
          Thread.sleep(100);
        } catch (InterruptedException e) {
        }
        t.interrupt();
      }

    输出为:

    false

    捕获到InterruptedException,通常表示希望结束该线程,线程大概有两种处理方式:

      • 向上传递该异常,这使得该方法也变成了一个可中断的方法,需要调用者进行处理。
      • 有些情况,不能向上传递异常,比如Thread的run方法,它的声明是固定的,不能抛出任何受检异常,这时,应该捕获异常,进行合适的清理操作,清理后,一般应该调用Thread的interrupt方法设置中断标志位,使得其他代码有办法知道它发生了中断。

    BLOCKED

    如果线程在等待锁,对线程对象调用interrupt()只是会设置线程的中断标志位,线程依然会处于BLOCKED状态,也就是说,interrupt()并不能使一个在等待锁的线程真正"中断"。
    使用synchronized关键字获取锁的过程中不响应中断请求,这是synchronized的局限性。如果这对程序是一个问题,应该使用显式锁。

     

    总结

    interrupt方法不一定会真正"中断"线程,它只是一种协作机制,如果不明白线程在做什么,不应该贸然的调用线程的interrupt方法,以为这样就能取消线程。
    对于以线程提供服务的程序模块而言,它应该封装取消/关闭操作,提供单独的取消/关闭方法给调用者,外部调用者应该调用这些方法而不是直接调用interrupt。

  • 相关阅读:
    常用正则表达式(数字、字符、固定格式)
    阿里云serverless使用笔记
    http的get请求与post请求区别
    HTTPS各版本安全策略HTTPS1_1_TLS1_0、HTTPS2_TLS1_0、HTTPS2_TLS1_2
    REST式的web服务
    JAVA Remote Object
    AJAX的核心XMLHttpRequest对象
    SQL中TOP,LIMIT,ROWNUM的用法
    半双工模式和全双工模式
    win7系统网卡驱动正常,网线连接设备正常,但电脑右下角网络图片显示一直在转圈或者显示一个黄色感叹号的解决办法
  • 原文地址:https://www.cnblogs.com/JackPn/p/9426518.html
Copyright © 2020-2023  润新知