在项目中自己提炼出了插件模式的一种设计方案,场景如下:
比如当某个模块a依赖n多个线程,模块a有个控制开关,可以一起启动n个线程或者停止n个线程,并且还可以指定线程名进行重启,如何有效的去管理呢,直接上代码
1.SmallPlug 插件接口文件
/**
* 小插件初始化,停止,运行
*/
public interface SmallPlug {
/**
* 初始化
*/
void initPlus();
/**
* 启动插件
*/
void startPlus();
/**
* 停止插件
*/
void stopPlus();
}
2.插件线程基础类:
/**
* 插件线程基础类
*/
public class BaseThreadPlus implements SmallPlug {
public String getThreadName() {
return threadName;
}
public Thread getSelfThread() {
return selfThread;
}
public AbstractRunable getSelfRunable() {
return selfRunable;
}
private String threadName="";
private Thread selfThread=null;
private AbstractRunable selfRunable=null;
public BaseThreadPlus(String threadName, AbstractRunable runnable){
this.threadName=threadName+"-"+DateUtil.now();
this.selfRunable=runnable;
}
@Override
public void initPlus() {
}
@Override
public void startPlus() {
Thread t = new Thread(selfRunable);
t.setName(threadName);
selfThread=t;
selfRunable.run=true;
t.start();
}
@Override
public void stopPlus() {
selfRunable.run=false;
selfThread.interrupt();
}
//无构造函数初始化线程
public static BaseThreadPlus loadBaseThreadPlus(String threadName, Class classs){
AbstractRunable runableObj= (AbstractRunable) ReflectUtil.newInstance(classs);
BaseThreadPlus plus= ReflectUtil.newInstance(BaseThreadPlus.class,threadName,runableObj);
return plus;
}
//有构造函数初始化线程
public static BaseThreadPlus loadBaseThreadPlus(String threadName, Class classs,Object... param){
AbstractRunable runableObj= (AbstractRunable) ReflectUtil.newInstance(classs,param);
BaseThreadPlus plus= ReflectUtil.newInstance(BaseThreadPlus.class,threadName,runableObj);
return plus;
}
}
3.抽象任务执行类
public abstract class AbstractRunable implements Runnable {
public volatile boolean run=false;
@Override
public abstract void run();
}
4.具体的业务执行者A,B类
@Slf4j
public class WorkDemoARunable extends AbstractRunable {
@Override
public void run() {
while (this.run){
try {
try {
log.info("执行后台复杂任务A");
Thread.sleep(1000*30);
} catch (InterruptedException e) {
log.error("WorkDemoARunable 被中断",e);
}
} catch (Exception e) {
log.error("WorkDemoARunable 处理异常:",e);
}catch (Throwable e){
log.error("WorkDemoARunable 崩溃:",e);
}
}
}
}
@Slf4j
public class WorkDemoBRunable extends AbstractRunable {
@Override
public void run() {
while (this.run){
try {
try {
log.info("执行后台复杂任务B");
Thread.sleep(1000*30);
} catch (InterruptedException e) {
log.error("WorkDemoBRunable 被中断",e);
}
} catch (Exception e) {
log.error("WorkDemoBRunable 处理异常:",e);
}catch (Throwable e){
log.error("WorkDemoBRunable 崩溃:",e);
}
}
}
}
5.模块的引导程序
/**
* 调度功能模块A
*/
@Service
@Slf4j
public class DispatchBoot implements SmallPlug{
private Map<String,BaseThreadPlus> plugThreadMap=new LinkedHashMap<>();
//调度引导程序状态
private volatile boolean isRun= false;
@Autowired
private StationService stationService;
@Override
public synchronized void initPlus() {
if (MapUtil.isNotEmpty(plugThreadMap)){
stopPlus();
}
//加载插件线程1
BaseThreadPlus plusA= BaseThreadPlus.loadBaseThreadPlus(WorkDemoARunable.class.getSimpleName(),
WorkDemoARunable.class);
plugThreadMap.put(WorkDemoARunable.class.getSimpleName(),plusA);
//加载插件线程2
BaseThreadPlus plusB= BaseThreadPlus.loadBaseThreadPlus(WorkDemoBRunable.class.getSimpleName(),
WorkDemoBRunable.class);
plugThreadMap.put(WorkDemoBRunable.class.getSimpleName(),plusB);
log.info("初始化完成插件线程");
}
@Override
public synchronized void startPlus() {
if (isRun){
log.info("采集插件线程已经在运行,必选先停止其运行");
return;
}
plugThreadMap.forEach((k,v)->{
v.startPlus();
});
isRun=true;
log.info("已启动所有的采集插件线程");
}
//停止当前所有插件线程
@Override
public synchronized void stopPlus() {
plugThreadMap.forEach((k,v)->{
v.stopPlus();
});
isRun=false;
plugThreadMap.clear();
log.info("停止完成采集插件线程");
}
/**
* 根据key来搜索线程
* @param plusKey
* @return
*/
public BaseThreadPlus getPlusByKey(String plusKey){
return plugThreadMap.get(plusKey);
}
/**
* 搜索插件线程
* @param namePrefix
* @return
*/
private List<BaseThreadPlus> findThreadPlus(String namePrefix){
List<BaseThreadPlus> list=new ArrayList<>();
for (Map.Entry<String, BaseThreadPlus> entry : plugThreadMap.entrySet()) {
if (entry.getKey().startsWith(namePrefix)){
list.add(entry.getValue());
}
}
return list;
}
/**
* 中断插件线程
* @param namePrefix
*/
public void interruptPlus(String namePrefix){
List<BaseThreadPlus> list=findThreadPlus(namePrefix);
if (CollUtil.isNotEmpty(list)){
list.forEach(e->{
e.getSelfThread().interrupt();
});
}
};
public static void main(String[] args) {
//模块A自己也是个插件,可以集成到业务模块中
DispatchBoot boot=new DispatchBoot();
boot.initPlus();
boot.startPlus();
}
}
6.执行DispatchBoot 的main方法,后输出如下,是不是对线程管理更好了,DispatchBoot 还提供了线程查找,中断等常用功能,DispatchBoot 其实自己也是个插件,可以插入到其他业务中,其他的业务只需要调用initPlus,startPlus,stopPlus即可