先上代码
@Override
public Result submitJobRunTimeTask(ClusterReq req) {
executorService.submit(() -> {
try {
req.setActivityName("computeRunTime");
ComputeResult computeResult = (ComputeResult) computeRunTime.compute(req);
InsertReq insertReq = new InsertReq(computeResult,req.getClusterName(),req.getActivityName(),req.getStrategy(),computeResult.getUpdateTime(),computeResult.getNextBeginDateTime());
System.out.println(insertReq.getActivityName());
insertask.insertJobRunTime(insertReq);
} catch (Exception e) {
logger.error("任务执行过程中发生错误", e);
}
});
return new SubmitResult(Constants.ActivityState.CLOSE.getCode(), Constants.ActivityState.CLOSE.getInfo());
}
@Override
public Result submitJobCpuRunTimeTask(ClusterReq req) {
executorService.submit(() -> {
try {
req.setActivityName("computeCpuRunTime");
ComputeResult computeResult = (ComputeResult) computeCpuRunTime.compute(req);
InsertReq insertReq = new InsertReq(computeResult,req.getClusterName(),req.getActivityName(),req.getStrategy(),computeResult.getUpdateTime(),computeResult.getNextBeginDateTime());
insertask.insertJobCpuRunTime(insertReq);
} catch (Exception e) {
logger.error("任务执行过程中发生错误", e);
}
});
return new SubmitResult(Constants.ActivityState.CLOSE.getCode(), Constants.ActivityState.CLOSE.getInfo());
}
问题
两个方法的请求参数都说req,并且都对req使用了setActivityName,因此req是在线程池内是一个共享变量。当两个线程用setActivityName修改req时就会发生线程安全问题。
解决思路
- ThreadLocal:将共享变量单独复制给线程池内的线程ThreadLocal,然而因为线程池内的线程是动态创建、销毁、复用,所以管理好ThreadLocal的生命周期很麻烦!!!!!
- 创建枚举对象:避免对req进行修改,创建枚举对象来赋值给insertReq,具体代码如下:
@Override
public Result submitJobRunTimeTask(ClusterReq req) {
executorService.submit(() -> {
try {
ComputeResult computeResult = (ComputeResult) computeRunTime.compute(req);
InsertReq insertReq = new InsertReq(computeResult,req.getClusterName(), Constants.ActivityName.COMPUTE_RUN_TIME.getCode(),req.getStrategy(),computeResult.getUpdateTime(),computeResult.getNextBeginDateTime());
insertask.insertJobRunTime(insertReq);
} catch (Exception e) {
logger.error("任务执行过程中发生错误", e);
}
});
return new SubmitResult(Constants.ActivityState.CLOSE.getCode(), Constants.ActivityState.CLOSE.getInfo());
}
@Override
public Result submitJobCpuRunTimeTask(ClusterReq req) {
executorService.submit(() -> {
try {
ComputeResult computeResult = (ComputeResult) computeCpuRunTime.compute(req);
InsertReq insertReq = new InsertReq(computeResult,req.getClusterName(),Constants.ActivityName.COMPUTE_CPU_RUN_TIME.getCode(),req.getStrategy(),computeResult.getUpdateTime(),computeResult.getNextBeginDateTime());
insertask.insertJobCpuRunTime(insertReq);
} catch (Exception e) {
logger.error("任务执行过程中发生错误", e);
}
});
return new SubmitResult(Constants.ActivityState.CLOSE.getCode(), Constants.ActivityState.CLOSE.getInfo());
}
总结
多线程编程时,应该尽量减少对共享变量的修改操作,从而减少数据竞争问题所导致的线程安全、性能下降等问题