以前的一段时间,做首页数据报表功能时,采用了多线程分治的方式来处理(虽然后面因为考虑到数据量太大不适合将数据拉取到内存中处理而放弃),那时候留下了一个疑问,我需要保证所有线程都执行完之后然后处理数据吗,因此需要做到线程协同合作,一开始我马上使用了countDownLacth来进行协同实现,后来采用了线程池的submit,也同样达到了协同(等待所有线程处理完)的效果。
这是以前的一个疑惑:https://blink.csdn.net/details/823641
不过没有大佬回答我....在自己沉淀一段时间后实力有了提升,我现在卷土重来,自己解决这个疑惑!
在这个方法中,测试了线程池的execute方法,是异步的,没啥问题!
里面有一个细节,因为execute只接受Runnable接口,但是我们的任务又是callable接口,通过观察FuterTask类,可以发现他是继承于Runnable接口的,因此需要用到FuterTask来进行转换适配。
还有一点我觉得,这个FuterTask名字起的很好,首先很明确,runnable这个接口只是一个任务,一些初学者经常会把runnable与现场混为一谈(我一开始也是!) 实际上,它们只是一个简单的任务,就是指示线程要去做什么的,因此这个命名很明确!
第二次测试:submit
在这个方法中我们测试了线程池的submit方法,从表现上来看,推断这是一种排队的方式执行的任务,也可以理解为同步的线程池.....本来使用线程池就是希望做到异步处理,咳咳....是异步了,但是没完全异步。
接下来我们探究一下源码,看看submit他是做了什么操作!:
啊这....翻车了,submit实际上和我们做的execute测试类似。。。帮我们进行了callable的转换,然后还是执行了execute方法.....
那到底是为啥....接下来通过几个测试例子研究一下:
....省略过程,直接说结论吧
经过排查发现,是因为调用了 futur.get方法,导致主线程进入阻塞,从而发生了让我们看起来像是任务排队的现象。接下来看一下get()的源码
get的会获取当前任务的执行状态,判断是否完成,如果未完成,会进入到awaitDone方法,自选询问状态,直到成功为止。然后获取报告....接下来我们去看一下awaitDone方法!
有以下的情况:
检测执行任务的线程 是否发生异常,是的话则在阻塞队列中移除它!
如果状态非正常,则返回状态值!
如果当前的等待节点引用为null,则获取最新一个等待节点!
如果以上情况都没发生,那么通过Unsafe类,由系统底层调用CAS,自旋将下一个等待节点替换到当前等待节点。如果成功则说明当前任务已经执行完毕,可以获取返回结果!