• java中的线程中断


    1、线程中断 即 线程的取消/关闭的机制

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

    停止线程,但这个方法被标记为了过时。
    @Deprecated
    public final void stop()
    =========================
    返回对应线程的中断标志位是否为truepublic boolean isInterrupted()
    返回当前线程的中断标志位是否为true,并清空中断标志位。
    public static boolean interrupted()
    表示中断对应的线程。
    public void interrupt()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、线程对中断interrupt()的反应

    2.1、RUNNABLE:线程在运行或具备运行条件只是在等待操作系统调度

    举个栗子:

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("线程t 执行中...");
            }
        });
        t.start();
        Thread.sleep(1);
        
        t.interrupt();
        System.out.println("main exit");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    RUNNABLE状态的线程tinterrupt()后,是否终止中断线程由线程t自身代码逻辑决定。

    2.2、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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    举个栗子:

    public class ThreadInterrupt {
        public static void main(String[] args) {
            Thread t = new Thread(() -> {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    System.out.println("Thread.interrupted() = " + Thread.interrupted());
                    //Thread.interrupted() = false
                    System.out.println("Thread.interrupted() = " + Thread.interrupted());
                    //Thread.interrupted() = false
                }
            });
            t.start();
    
            t.interrupt();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    捕获到InterruptedException,通常表示希望结束该线程,线程大概有两种处理方式:
    向上传递该异常,这使得该方法也变成了一个可中断的方法,需要调用者进行处理。

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

    2.3、BLOCKED:线程在等待锁,试图进入同步块

    举个栗子:

    public class ThreadInterrupt {
        private final static Object lockObj = new Object();
    
        private static class MyBlockedThread extends Thread {
            @Override
            public void run() {
                System.out.println("MyBlockedThread.run = " + Thread.currentThread().isInterrupted());
                synchronized (lockObj) {
                    while (!Thread.currentThread().isInterrupted()) {
                        System.out.println(Thread.currentThread().isInterrupted());
                    }
                }
                System.out.println("exit");
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            synchronized (lockObj) {
                MyBlockedThread myBlockedThread = new MyBlockedThread();
                myBlockedThread.start();
                Thread.sleep(3000);
                myBlockedThread.interrupt();
                myBlockedThread.join(); // join方法会等待线程执行完后返回
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    myBlockedThread.join();该行代码放开注释掉情况下:线程一直等待锁 BLOCKED。

    com.michael.ThreadInterrupt.MyBlockedThread.run = false
    
    • 1

    myBlockedThread.join();该行代码注释掉情况下:因为主线程不再等待线程myBlockedThread结束,释放锁lock后,线程myBlockedThread会获得锁,然后检测到发生了中断,然后程序退出。

    com.michael.ThreadInterrupt.MyBlockedThread.run = false
    exit
    
    • 1
    • 2

    2.4、NEW/TERMINATED:线程还未启动或已结束

    举个栗子:

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            System.out.println("线程t 执行...");
        });
        t.interrupt();
        System.out.println("NEW = " + t.isInterrupted());
    
        t.start();
        Thread.sleep(100);
        t.interrupt();
        System.out.println("TERMINATE = " + t.isInterrupted());
    }
    
    ============ 执行结果 ============
    NEW = false
    线程t 执行...
    TERMINATE = false
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.5、IO操作

    如果线程在等待IO操作,尤其是网络IO,则会有一些特殊的处理。

    • 如果IO通道是可中断的,即实现了InterruptibleChannel接口,则线程的中断标志位会被设置,同时线程会收到异常ClosedByInterruptException
    • 如果线程阻塞于Selector调用,则线程的中断标志位会被设置,同时阻塞的调用会立即返回。
    • InputStream的read调用,该操作是不可中断的,如果流中没有数据,read会阻塞 (但线程状态依然是RUNNABLE),且不响应interrupt(),与synchronized类似,调用interrupt()只会设置线程的中断标志,而不会真正"中断"。

    3、关于中断的经验

    Java中取消/关闭线程技术是中断,但它是一种协作机制,不会强制终止线程。线程在不同状态IO操作时对中断的反应有所不同。
    作为线程的实现者:应该提供明确的取消/关闭方法,并用文档描述清楚其行为。
    作为线程的调用者:应该使用其取消/关闭方法,而不是贸然调用interrupt()方法。

  • 相关阅读:
    IDEA使用Maven
    力扣HOT100 - 994. 腐烂的橘子
    阿里技术官手码 12W 字面试小册
    Redis 的事务操作
    ELK 企业级日志分析系统
    C语言 位操作符 >> << & | ^
    司徒理财:10.12黄金CPI预期升温、今日最新走势操作策略
    python - random函数
    Metasploit——辅助模块(Auxiliary)
    nginx源码分析-字符串
  • 原文地址:https://blog.csdn.net/Michael_lcf/article/details/109514679