2020.8.6
今天早晨的站会上,老大提出了一个问题,昨天本人写的确保任务单线程的方法不太好:
public static Thread nowThread = null;
--------------------------------------------------
if(nowThread != null && nowThread.isAlive()){
LOG.info("当前存在正在执行的线程,本次线程不执行,请稍后再试");
return;
}
else{
nowThread = Thread.currentThread();
}
//主要代码省略
......
//线程执行完毕,置空
nowThread = null;
这段代码的逻辑没问题,只是,
当sonarqube检查时,会降低代码合格率,因为它要求static变量是final的。
1.保证上一次方法执行完毕后再执行下一次方法
会后,老大建议本人这么写:
https://blog.csdn.net/u013066244/article/details/52450142
https://my.oschina.net/blueskyer/blog/325812
这个意思是说,Quartz(import org.quartz.Job)的定时任务默认都是并发执行的,不会等待上一次任务执行完毕,只要间隔时间到就会执行;如果用到了spring框架,想设置为上一次任务执行后才能执行下一次任务的模式(单任务模式),就需要在xml文件中增加这一句(你添加定时任务的xml那里):
<property name="concurrent" value="false" />
如果只用了Quartz而没有用到spring,可以在你定时任务的类上添加这个注解:
@DisallowConcurrentExecution
这样该类中的同一个定时任务方法就不能同时执行了;不过该类中不同的定时任务方法还是可以同时执行的。
【其实我们的项目中并没有用到import org.quartz.Job之类的,老大是让我参考这个文章,找找spring中类似的配置文件方法。】
好吧,这样确实可以保证定时任务指定的方法实现单线程模式了;
问题是通过接口手动调用该方法(url)时如何保证单线程模式呢?
本人的项目中,这个方法既可以通过定时任务执行,也可以通过调用接口手动执行;并且这个方法需要保证单线程模式:
【调用一次方法后,调用第二次该方法,如果上一次方法没有执行完毕,则第二次不能执行。】
老大想了想,最后说:“那先这样吧(还按目前的方法)。”
2.绕开sonarqube检查
老大回去后,本人首先感觉sonarqube的检查不合理,为啥static类型的变量必须是final类型的呢?那需要一个全局对象并且会不断改变该对象的值的情况要怎么办?
琢磨了半天,本人想到了以下几个方法:
1.可以创建一个单例类,将全局对象存入该单例类即可实现随时存取随时改变对象的值的操作;但是又担心java虚拟机会将单例对象回收掉(如果较长时间没有用到该对象就会被回收),那样就无法实现长时间保存的效果了;
2.可以把对象存入spring容器中,这样也能实现长时间保存、随时存取修改,但是感觉还是不太方便(影响整体代码结构,spring容器中多了一个只有我一个人使用的对象......)
3.在方法附近声明一个内部final类,好像还是不太好......
......
最终,本人选择了这么写:
public final static HashMap<String,Thread> threadMap = new HashMap<>();
--------------------------------------------------
Thread nowThread = threadMap.get("nowThread");
if(nowThread != null && nowThread.isAlive()){
LOG.info("当前存在正在执行的线程,本次线程不执行,请稍后再试");
return;
}
else{
threadMap.put("nowThread",Thread.currentThread());
}
//主要代码省略
......
//线程执行完毕,置空
threadMap.put("nowThread",null);
使用final static的HashMap来保存Thread对象,这样就实现了长时间保存、随时存取修改、以及避开sonarqube的检查了。
PS:老大开会还建议,为了避免merge代码时混乱,不要频繁提交svn,等修改了一个大功能后再提交;
于是本人准备每日下班时提交,到底能否避开sonarqube的检查,明天应该就知道了。