定义线程池对象
public class SingletonThreadPool {
//核心线程参数
private static final int CORE_POOL_SIZE = 10;
//最大线程数
private static final int MAXIMUM_POOL_SIZE = 50;
//时间
private static final long KEEP_ALIVE_TIME = 3;
//时间单位
private static final TimeUnit UNIT = TimeUnit.MINUTES;
//工作队列
private static final BlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(50);
//对象
private static final ThreadPoolExecutor EXECUTOR;
// 私有构造器,防止外部通过new创建实例
private SingletonThreadPool() {
}
// 静态初始化块,创建线程池实例
static {
EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, UNIT, WORK_QUEUE,
new ThreadPoolExecutor.CallerRunsPolicy());
}
// 提供全局访问点获取线程池实例
public static ThreadPoolExecutor getExecutor() {
return EXECUTOR;
}
}
Service层
@Transactional
public synchronized String createDataCenter(DataCenterSaveReqVO createReqVO) {
createReqVO.setId(IdUtil.getSnowflakeNextIdStr());
// 插入
DataCenterDO dataCenter = BeanUtils.toBean(createReqVO, DataCenterDO.class);
//创建Runable类
ThreadPoolExecutor executor = SingletonThreadPool.getExecutor();
//发送
executor.execute(new AlarmDataCheck(alarmSettingMapper,alarmDataMapper,dataCenter,dataCenterMapper,alarmDataProcessingMapper,partInfoMapper));
// 返回
return dataCenter.getId();
}
为什么要使用
executor.execute(); 没有返回值,因为线程对象对该方法的返回值设置为void,而且如果方法中抛出的异常,也不会终止当前方法,他的传入对象也必须为Runable或者实现了Runable的对象; executor.submit(); 有返回值,其中对象必须是且Callable才行,或者实现了Callable的对象才可以;
很多人没搞懂,为什么可以传入对象,现在甚至很多人对忘记了,匿名内部类的使用
executor.execute(new Runnable() {
@Override
public void run() {
}
});
反而现在使用了Lambda,都忘记了里面传入的是什么对象
executor.execute(()->{});
其实在这里系统会默认给你匹配,是Runable还是Callable对象
但是,我这里直接传入了一个实现了Runable的对象,为什么呢,因为这样所有的逻辑都存在一个对象中,更加易于维护和拓展
@Component
@NoArgsConstructor
@Scope("prototype")
public class AlarmDataCheck implements Runnable{
public AlarmDataCheck(AlarmSettingMapper alarmSettingMapper,
AlarmDataMapper alarmDataMapper,
DataCenterDO dataCenter,
DataCenterMapper dataCenterMapper,
AlarmDataProcessingMapper alarmDataProcessingMapper,
PartInfoMapper partInfoMapper) {
this.alarmSettingMapper = alarmSettingMapper;
this.alarmDataMapper = alarmDataMapper;
this.dataCenter = dataCenter;
this.dataCenterMapper = dataCenterMapper;
this.alarmDataProcessingMapper = alarmDataProcessingMapper;
this.partInfoMapper = partInfoMapper;
}
//通过有参构造像alarmSettingDO传入对象
@Override
public void run() {
dataCenterMapper.insert(dataCenter);
if (warningChecks(dataCenter)){
dataCenter.setReserveTwo(alarmSettingDO.getReserveOne()).setIsAlarming("1");
dataCenterMapper.updateById(dataCenter);
}
//先获取传感器id,根据传感器id查询
PartInfoDO partInfoDO = partInfoMapper.selectOne(PartInfoDO::getSensorId, dataCenter.getReserveOne());
partInfoDO.setState(alarmSettingDO == null ?"0":"3".equals(alarmSettingDO.getReserveOne())?"4":alarmSettingDO.getReserveOne());
//更新部件磨损状态
partInfoMapper.updateById(partInfoDO);
}
在这里由于线程池的启动太快原因导致无法自动注入,我采取了有参构造的方法,我试过懒加载不好使,如果大家,有什么好的方法,欢迎提供
以下是submit的使用教程,以及对应的方法,我的建议是根据情况选择是否要采用submit方法,因为他可以校验线程池中的任务是否执行完毕