采用共享变量+Callable的方式

需求:将同步代码改成多线程

原始同步代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  JSONObject resultJson=new JSONObject();
//查询该用户是否存在该任务
patrolDevice.setHead_people_id_number(userService.getUserDetailAndCheckIdNumber(token));
List<PatrolDevice> results=patrolDeviceDao.queryDeviceByObjectNoPagination(patrolDevice);
if(results.isEmpty() || results.size()>1){
throw new MissingArgumentException("本设备不属于当前登录人员的巡检任务");
}
PatrolDevice resultDevice=results.get(0);
if(resultDevice.getDevice_type()==null){
throw new MissingArgumentException("获取巡检任务类型异常,获取检查项失败,请完善巡检任务基础信息");
}
long interval= TimeUtil.getExpireIntervalByExpireTime(resultDevice.getExpiry_time());
resultDevice.setExpire_interval(interval);
List<PatrolCheckItem>resultItems=patrolCheckItemDao.queryCheckItemByTypeName(new PatrolDeviceType(resultDevice.getDevice_type()));
AppUser resultUser = userService.getUserDetail(token);

resultJson.put("checkItem",resultItems);
resultJson.put("taskDetail", resultDevice);
resultJson.put("userDetail", resultUser);
return resultJson;

改进成多线程方式

首先使用ExecutorService线程池固定生成三个线程:

  • 身份验证线程

  • 用户详情查询线程

  • 任务详情查询功能

但是,后两种线程需要第一个线程的执行结果,且三个线程需要共同将执行结果put到结果json类中,期间用户详情查询线程需要根据身份验证线程的返回结果作补充

采用Future父类接受执行结果,利用get()函数阻塞,实现在身份验证线程执行完后,在异步执行后两种线程。自定义有参构造函数,实现参数的接续传递和共享。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public JSONObject queryCheckTaskDetailByUserToken(String token, PatrolDevice patrolDevice) throws MissingArgumentException {
JSONObject resultJson=new JSONObject();

ExecutorService executorService = Executors.newFixedThreadPool(3);

try {
Future<PatrolDevice> futureIdentifier = executorService.submit(new IdentifierTask(patrolDevice,token));
PatrolDevice resultDevice=futureIdentifier.get();
Future<List<PatrolCheckItem>> futurePatrolTask = executorService.submit(new FetchPatrolTask(resultDevice,resultJson));
Future<AppUser> futureUser = executorService.submit(new FetchUserDetail(token,resultJson));
if(futurePatrolTask.get()==null && futureUser.get()==null){
return resultJson;
}
}catch (Exception e){
executorService.shutdown();
throw new MissingArgumentException(e.getMessage());
}
return resultJson;
}

//线程任务类
class IdentifierTask implements Callable<PatrolDevice> {
public PatrolDevice patrolDevice;
public String token;

public IdentifierTask(PatrolDevice patrolDevice, String token) {
this.patrolDevice = patrolDevice;
this.token = token;
}
@Override
public PatrolDevice call() throws Exception {
patrolDevice.setHead_people_id_number(userService.getUserDetailAndCheckIdNumber(token));
List<PatrolDevice> results=patrolDeviceDao.queryDeviceByObjectNoPagination(patrolDevice);
if(results.isEmpty() || results.size()>1){
throw new MissingArgumentException("本设备不属于当前登录人员的巡检任务");
}
return results.get(0);
}
}

class FetchPatrolTask implements Callable<List<PatrolCheckItem>>{
public PatrolDevice resultDevice;
public JSONObject resultJson;

public FetchPatrolTask(PatrolDevice resultDevice, JSONObject resultJson) {
this.resultDevice = resultDevice;
this.resultJson = resultJson;
}

@Override
public List<PatrolCheckItem> call() throws Exception {
if(resultDevice.getDevice_type()==null){
throw new MissingArgumentException("获取巡检任务类型异常,获取检查项失败,请完善巡检任务基础信息");
}
long interval= TimeUtil.getExpireIntervalByExpireTime(resultDevice.getExpiry_time());
resultDevice.setExpire_interval(interval);
List<PatrolCheckItem>resultItems=patrolCheckItemDao.queryCheckItemByTypeName(new PatrolDeviceType(resultDevice.getDevice_type()));
resultJson.put("checkItem",resultItems);
resultJson.put("taskDetail", resultDevice);
return null;
}
}

class FetchUserDetail implements Callable<AppUser> {
public String token;
public JSONObject resultJson;

public FetchUserDetail(String token, JSONObject resultJson) {
this.token = token;
this.resultJson = resultJson;
}

@Override
public AppUser call() throws Exception {
AppUser resultUser = userService.getUserDetail(token);
resultJson.put("userDetail", resultUser);
return null;
}
}


性能测试

单线程10000次请求的压力测试,设定100ms的响应时间为标准:

通过 未通过
改进前 9106次 896次
改进后 9254 746

单线程100次压力测试,设定30ms的响应时间为标准

通过 未通过
改进前 53 47
改进后 58 42

单线程100次压力测试,设定10ms的响应时间为标准

通过 未通过
改进前 0 100
改进后 2 98

测试结果由于现场网络情况较差且不稳定原因,会有偏差,但是综合来看,改进后响应速度还是有提升,特别是在压力较大的情况下,提升较为明显。