目录
六、将使用Fork-Join和不使用Fork-Join做个对比:
一、什么是分而治之?
分而治之是一个算法设计思想,它就是把大问题分割为多个相同的小问题,并且小问题之间无关联,如果小问题之间有关联就叫做动态规划。像我们的归并排序算法就利用这个思想
二、Fork-Join就体现了分而治之
原理:就是在必要情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个小任务运算的结果进行join汇总起来。用一个图来理解理解(网上找的):
三、Fork-Join还实现了工作密取算法
工作密取就是:将大任务拆分成了一个个小任务,将小任务交给线程去完成,但是我们一般线程数和小任务数量是不对等的。然后线程就会有自己的一个任务列表,当线程A的任务做完了,但B线程还没有做完,这时A线程就会去B线程中的任务队列中偷偷的拿一个任务来做,做完了,就偷偷的放回去。
但我们不是分成了多个相同的小问题吗,那为什么会出现有的线程很早就完成了任务,而有的线程还在做呢?
举个栗子,你就明白了:我们将计算1+2+3+......+100000分割一下,1000为一个单位,第一个小任务:1+....+1000 ;第二个小任务:1001+...+2000;第三个任务:2001+...3000;第n个任务:(100000-999)+...+100000。看似每个任务都以1000为一个单位,去进行计算,但是你觉得 1+....+1000快,还是 (100000-999)+...+100000快呢?肯定是第一个快啊,位数少嘛,所以虽然大任务分成了多个相同的小任务,但小任务之间工作难度是有可能是不同的。
四、Fork-Join有一个使用的标准范式:
pool = new ForkJoinPool()
MyTask myTask = new ForkJoinTask()
Pool.invoke(myTask)
Result = myTask.join()
我们一般不会用ForkJoinTask而是用的RecursiveTask和RecursiveSction,有何区别呢?前者有返回值,后者无返回值
那我们在哪里拆分任务呢?——在compute方法中(RecursiveTask和RecursiveSction的抽象方法)
五、异步提交任务和同步提交任务
同步:一个操作必须在另一个操作完后开始执行,例如A,B,C:A->B->C
异步:任务可以并行执行,例如A,B,C: A B C同时执行
需要异步提交的时候,使用invloke方法
需要同步提交的时候,使用submit(有返回结果)/execute方法
六、将使用Fork-Join和不使用Fork-Join做个对比:
完成累加任务
1.不使用Fork-Join,开启一个线程完成任务,并计算线程完成任务花了多久:
结果:The count is 7998000 spend time:0ms
2.使用Fork-Join来完成任务:
结果:running......
running......
running......
Task is Running.....
The count is 7998000 spend time:4ms
为何使用了Fork-Join更耗时了呢?因为我们一般调用方法,都会把方法入栈,然后执行完毕,将方法出栈,使用Fork-Join,它内部一直在进行压栈入栈操作,再加上Fork-Join使用了多线程(会有线程之间的切换),我们使用单线程计算时,它就只顾着计算,啥也不干就计算,肯定耗的时间短。
如果加入一句休眠代码呢?会出现什么?将SleepTools.ms(1);打开
1.没有使用Fork-Join,结果为:
The count is 7998000 spend time:6197ms
2.使用了Fork-Join,结果为:
The count is 7998000 spend time:1404ms
从结果可以得出,使用Fork-Join比不使用Fork-Join快几倍,结论:任务量大、比较耗时时的时候可以使用Fork-Join。