JUC并发编程 -- 线程常用方法之interrupt 方法详解 & 设计模式之两阶段终止 & 打断 park 线程

Posted Z && Y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC并发编程 -- 线程常用方法之interrupt 方法详解 & 设计模式之两阶段终止 & 打断 park 线程相关的知识,希望对你有一定的参考价值。

1. 线程常用方法之interrupt 方法详解


1.1 打断阻塞方法

  • 打断 sleep,wait,join 的线程这几个方法都会让线程进入阻塞状态

打断阻塞的线程,会清空打断状态(打断标记记为false),以 sleep 为例:

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test11")
public class Test11 {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            try {
                Thread.sleep(5000); // wait, join
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1");

        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
        log.debug("t1 interrupt");
        log.debug("打断标记:{}", t1.isInterrupted());
    }
}

运行结果:


1.2 打断正常运行的线程

代码:

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test12")
public class Test12 {

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                // 正常运行的线程被打断后 该线程的打断标记会设置为true
                boolean interrupted = Thread.currentThread().isInterrupted();
                if (interrupted) {
                    log.debug("被打断了, 退出循环");
                    // 退出循环 因为该线程后面没有代码可以执行了, 所以这里相当于结束行程
                    break;
                }
            }
        }, "t1");
        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
    }
}

运行结果:


2. 设计模式之两阶段终止


2.1 原理

在一个线程T1中如何“优雅”终止线程T2?这里的【优雅】指的是给T2一个料理后事的机会。

错误思路:

设计模式之两阶段终止图解:



2.2 两阶段终止-interrupt实现

代码:

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.TwoPhaseTermination")
public class Test13 {
    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTermination tpt = new TwoPhaseTermination();
        tpt.start();

        Thread.sleep(3500);
        log.debug("停止监控");
        tpt.stop();
    }
}

@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination {
    // 监控线程
    private Thread monitorThread;

    // 启动监控线程
    public void start() {
        monitorThread = new Thread(() -> {
            while (true) {
                Thread currentThread = Thread.currentThread();
                if (currentThread.isInterrupted()) {
                    log.debug("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);
                    log.debug("执行监控记录");
                } catch (InterruptedException e) {
                    e.printStackTrace();
//                    重新设置打断标记
                    monitorThread.interrupt();
                }
            }
        }, "monitor");
        monitorThread.start();
    }

    // 停止监控线程
    public void stop() {
        monitorThread.interrupt();
    }
}

运行结果:


3. 打断 park 线程

LockSupport.park()方法是让当前线程进入阻塞状态:


3.1 park 线程展示

示例代码:

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.LockSupport;

@Slf4j(topic = "c.Test14")
public class Test14 {
    private static void test3() throws Exception {
        Thread t1 = new Thread(() -> {
            log.debug("park...");
            LockSupport.park();
            log.debug("unpark...");
            log.debug("打断状态:{}", Thread.currentThread().isInterrupted());
        }, "t1");
        t1.start();

//        Thread.sleep(1000);
//        t1.interrupt();
    }

    public static void main(String[] args) throws Exception {
        test3();
    }
}

运行结果(发现该线程进入阻塞状态):


3.2 打断park线程

现在的运行结果:


3.3 补充:

打断标记为真的情况下,再次使用park方法不起作用

示例代码:

运行结果:

如何让park方法再次起作用呢?==>重新设置打断标记

现在的运行结果:



以上是关于JUC并发编程 -- 线程常用方法之interrupt 方法详解 & 设计模式之两阶段终止 & 打断 park 线程的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 -- 线程常用方法之sleep() & yield() & 线程优先级 & sleep方法应用: 限制对 CPU 的使用

JUC并发编程 -- 线程常用方法概述 & start() vs run()

JUC并发编程 共享模式之工具 JUC 线程安全的集合类 -- 线程安全的集合类概述

JUC并发编程之CompletableFuture基础用法

JUC并发编程之CompletableFuture基础用法

JUC并发编程之CompletableFuture基础用法