今天周末,空闲状态下洗了澡舒舒服服的优哉游哉,刚好趁这个时间记一下工作日遇到的印象深刻的坑。
项目要求有一个定时轮询,主要用于在向第三方接口发送交易请求后,不断向该第三方的交易查询接口去查询交易结果信息。针对这个,我是想通过调用一个线程通过sleep()延时来不断发送查询结果请求,同时在该线程内使用循环判断语句在获得结果后结束线程,由于考虑到查询结果可能会需要记录,故考虑使用有返回值的线程。
一开始我是这么封装方法的——
public static String AskOrderResurt(String merchantNo, String orderNo, String key, int delay){
String result = "";
ExecutorService service = Executors.newSingleThreadScheduledExecutor();
Future<String> future = service.submit(()->{
String str = null;
while(true){
str = queryOrder(merchantNo, orderNo, key);//调用发送查询请求方法
if(str==null){//这里是为了测试一旦出现未获取到返回的情况下进行不断定时情况的,所以设为==
break;
}
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(delay*3000);
}catch (Exception e){
}
}
return str;
});
try {
result = future.get();
}catch (Exception e){
}
service.shutdown();
return result;
}
咋看没有问题,但在主线程内调用该方法后,却发现子线程一直占用cpu,而主线程完全不进行,==串行运行,很诡异,我的想法是,在子线程sleep的时候,主线程总能争抢到执行权,从而轮询的子线程不影响主线程进行,结果却阻塞了!
经过很长时间的查看、思考测试,终于发现了问题——
result = future.get();
future.get()获取线程返回值是一个阻塞的方法,正是该方法导致了问题。
最后,询问了公司同事,被告知可以考虑在子线程内采用持久化返回值到db的某临时表内,再取值判断来替代需要直接取线程返回值的方法,在请求多时,相对容易控制请求数量。