今天小编接到了一个给砸门APP推送消息的由一个需求,由于会同时给很多设备推送消息,于是小编就想到用线程池来实现异步推送。在嘎嘎码完代码之后,就开始自己冒烟单测了,测试也很简单就是在单元测试跑一下自己代码就好了,于是在跑代码过程中发现线程池里面的代码执行看一半,第一反应看代码,是不是哪的逻辑退出,或者出现异常了。一通检查发现没有,于是我尝试把线程池去掉然后跑代码,惊奇的发现代码跑完了。后面我写了个test模拟这种情况,直接上代码:
private static final ExecutorService fixedThreadPool = new ThreadPoolExecutor(10, 20,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(5000));
@Test
public void test2() {
System.out.println(0);
try {
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("给自己微信充500w");
//给自己支付宝充500w 花费5秒
Thread.sleep(5000);
System.out.println(111);
} catch (Exception e) {
System.out.println(222);
}
}
});
}catch (Exception e){
System.out.println(333);
}
}
输出结果:
0
给自己微信充500w。
这里就比较迷惑了,按道理111也会输出啊,为啥睡眠了5秒之后就不输出了呢?
好了这里就不卖关子啦,大家都知道 线程是依赖于进程执行的,相信大家都背过线程和进程的八股文。那么这个地方流程是 首先这个test会开启一个进程,然后会有一个主线程去执行第一行输出0的这行代码,然后走到下一步 我们使用线程池去执行我们的代码,这时候线程池会开启子线程去执行里面的逻辑,二者是并行的(这里就不考虑微观,宏观,单核等因素),而在线程池执行到睡眠5秒那行代码的时候,子线程进行等待,但是这时候主线程已经执行完了,主线程退出后,进程也没了,所以子线程的代码就执行不下去了。
小编又去回溯直接的业务代码,发现确实有一行代码特别耗时,才导致子进程没有执行完就结束了,为了测试完代码,只需要让主线程也睡眠几秒就好了。那么问题来了,难道在沙箱,生产环境中我们也要睡眠主线程么,这不是严重影响效率么。其实也不用,test是因为当前这个实例跑完代码之后就释放了,而我们在生产环境的业务代码,这个实例是会一直存在的,直到你被gc掉,所以会执行完子线程哒。