【JUC并发】黑马程序员:终止模式之线程优雅打断,interrupt版、打断标记+volatile版

发布于:2023-02-05 ⋅ 阅读:(1026) ⋅ 点赞:(0)

场景介绍

设计一个单例的监控类,实现 开启 和 停止 功能。

interrupt版

实现

/**
 * 监控类:创建成员线程变量,执行监控任务。提供 开启 和 停止 功能。
 */
@Slf4j(topic = "c.five-Demo1")
final class TPTInterrupt{
	//1.单例模式固定套路。详细单例模式介绍参考文章《单例模式正确姿势汇总——普通饿汉式,枚举饿汉式,普通懒汉式,DCL懒汉式,静态内部类懒汉式》
    private static volatile TPTInterrupt tptInterrupt;
    //线程名字
    private final String name;
    private TPTVolatile(){}
    private TPTInterrupt(String value){
        name=value;
    }
    //2.创建监控类具体任务执行线程
    private final Thread thread=new Thread(()->{
        Thread current=Thread.currentThread();
        while(true){
        	//2.1 判断是否调用 停止 方法。
            if(current.isInterrupted()){
                log.debug("被打断-料理后事");
                break;
            }
            log.debug("执行监控任务");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                log.debug("睡眠时(模拟执行监控任务)被打断");
                current.interrupt();
            }
        }
    },"TPT");
    //开启监控
    public final void startTPT(){
        try{
            thread.start();
        }catch (IllegalThreadStateException e){
            System.out.println("监控进程无法被多次调用");
        }
    }
    //停止监控
    public final void stopTPT(){
    	//调用线程的打断方法
        thread.interrupt();
    }
    //获取监控对象:单例模式固定套路
    public static TPTInterrupt getTPTInterrupt(){
        if(tptInterrupt!=null){
            return tptInterrupt;
        }else {
            synchronized (TPTInterrupt.class){
                if(tptInterrupt!=null){
                    return tptInterrupt;
                }
                tptInterrupt=new TPTInterrupt("后台监控线程");
                return tptInterrupt;
            }
        }
    }
}

测试

public static void main(String[] args) throws InterruptedException {
        //interrupt版
        TPTInterrupt tptInterrupt = TPTInterrupt.getTPTInterrupt();
        tptInterrupt.startTPT();
        tptInterrupt.startTPT();
        TimeUnit.SECONDS.sleep(2);
        tptInterrupt.stopTPT();

    }

效果

监控进程无法被多次调用
00:19:16 [TPT] c.five-Demo1 - 执行监控任务
00:19:17 [TPT] c.five-Demo1 - 执行监控任务
00:19:18 [TPT] c.five-Demo1 - 睡眠时(模拟执行监控任务)被打断
00:19:18 [TPT] c.five-Demo1 - 被打断-料理后事

打断标记+volatile版

实现

/**
 * 监控类:创建成员线程变量,执行监控任务。提供 开启 和 停止 功能。
 */
@Slf4j(topic = "c.five-Demo1")
final class TPTVolatile{
	//1.单例模式固定套路。详细单例模式介绍参考文章《单例模式正确姿势汇总——普通饿汉式,枚举饿汉式,普通懒汉式,DCL懒汉式,静态内部类懒汉式》
    private static volatile TPTVolatile tptVolatile;
    //2.打断标记。volatile 修饰:保证可见性,有序性
    private static volatile boolean interrupted=false;
    //3.线程名字
    private final String name;
    private TPTVolatile(){

    }
    private TPTVolatile(String name){
        this.name=name;
    }
    //4.创建监控类具体任务执行线程
    private final static Thread thread=new Thread(()->{
		//4.1 循环执行监控任务
        while(true){
        	//4.2 判断监控任务是否需要停止
            if(interrupted){
                log.debug("被打断-料理后事");
                break;
            }
            log.debug("执行监控任务");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                log.debug("睡眠时(模拟执行监控任务)被打断");
                interrupted=true;
            }
        }
    },"TPT");
    //开启监控线程
    public final void startTPT(){
        try{
            thread.start();
        }catch (IllegalThreadStateException e){
            System.out.println("监控进程无法被多次调用");
        }
    }
    //停止监控(打断监控线程)
    public final void stopTPT(){
        interrupted=true;
    }
    //获得监控对象
    public static TPTVolatile getTPTVolatile(){
        if(tptVolatile!=null){
            return tptVolatile;
        }else {
            synchronized (TPTVolatile.class){
                if(tptVolatile!=null){
                    return tptVolatile;
                }
                tptVolatile=new TPTVolatile("后台监控线程");
                return tptVolatile;
            }
        }
    }
}

测试

public static void main(String[] args) throws InterruptedException {
        //打断标记+volatile版
        TPTVolatile tptVolatile=TPTVolatile.getTPTVolatile();
        tptVolatile.startTPT();
        tptVolatile.startTPT();
        TimeUnit.SECONDS.sleep(2);
        tptVolatile.stopTPT();

    }

效果

监控进程无法被多次调用
00:21:07 [TPT] c.five-Demo1 - 执行监控任务
00:21:08 [TPT] c.five-Demo1 - 执行监控任务
00:21:09 [TPT] c.five-Demo1 - 被打断-料理后事

网站公告

今日签到

点亮在社区的每一天
去签到