场景介绍
设计一个单例的监控类,实现 开启 和 停止 功能。
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 - 被打断-料理后事