引言
先来看一些APP的获取数据,诸如此类,一个页面获取N多个,多达10个左右的一个用户行为数据,比如:点赞数,发布文章数,点赞数,消息数,关注数,收藏数,粉丝数,卡券数,红包数........... 真的是多~ 我们看些图:
![4f63be5b4fbdb94b049333294393c748.png](https://i-blog.csdnimg.cn/blog_migrate/c0f73d3d8898a5fffcf1db64a54078f6.jpeg)
![aceee2a07400d8ea9c2b86d5f71ee870.png](https://i-blog.csdnimg.cn/blog_migrate/4d3a5bb11e77c72494f27077cc507d25.jpeg)
平时要10+接口的去获取数据(因为当你10+个查询写一起,那估计到半分钟才能响应了),一个页面上N多接口,真是累死前端的宝宝了,前端开启多线程也累啊,我们做后端的要体量一下前端的宝宝们,毕竟有句话叫"程序员何苦为难程序员~ "
今天我们也可以一个接口将这些数据返回~ 还贼TM快,解决串行编程,阻塞编程带来的苦恼~
多线程并发执行任务,取结果归集
今天猪脚就是 Future、FutureTask、ExecutorService...
- 用上FutureTask任务获取结果老少皆宜,就是CPU有消耗。FutureTask也可以做闭锁(实现了Future的语义,表示一种抽象的可计算的结果)。通过把Callable(相当于一个可生成结果的Runnable)作为一个属性,进而把它自己作为一个执行器去继承Runnable,FutureTask 实际上就是一个支持取消行为的异步任务执行器 。
- Callable就是一个回调接口,可以泛型声明返回类型,而Runnable是线程去执行的方法.这个很简单~大家想深入了解就进去看源码好了~ 因为真的很简单~
- FutureTask实现了Future,提供了start, cancel, query等功能,并且实现了Runnable接口,可以提交给线程执行。
- Java并发工具类的三板斧 状态,队列,CAS
状态
/** * The run state of this task, initially NEW. The run state * transitions to a terminal state only in methods set, * setException, and cancel. During completion, state may take on * transient values of COMPLETING (while outcome is being set) or * INTERRUPTING (only while interrupting the runner to satisfy a * cancel(true)). Transitions from these intermediate to final * states use cheaper ordered/lazy writes because values are unique * and cannot be further modified. * * Possible state transitions: //可能发生的状态过度过程 * NEW -> COMPLETING -> NORMAL // 创建-->完成-->正常 * NEW -> COMPLETING -> EXCEPTIONAL // 创建-->完成-->异常 * NEW -> CANCELLED // 创建-->取消 * NEW -> INTERRUPTING -> INTERRUPTED // 创建-->中断中-->中断结束 */ privatevolatileint state; // 执行器状态 privatestaticfinalint NEW = 0; // 初始值 由构造函数保证 privatestaticfinalint COMPLETING = 1; // 完成进行时 正在设置任务结果 privatestaticfinalint NORMAL = 2; // 正常结束 任务正常执行完毕 privatestaticfinalint EXCEPTIONAL = 3; // 发生异常 任务执行过程中发生异常 privatestaticfinalint CANCELLED = 4; // 已经取消 任务已经取消 privatestaticfinalint INTERRUPTING = 5; // 中断进行时 正在中断运行任务的线程 privatestaticfinalint INTERRUPTED = 6; // 中断结束 任务被中断 /** The underlying callable; nulled out after running */ private Callable callable; /** The result to return or exception to throw from get() */ private Object outcome; // non-volatile, protected by state reads/writes /** The thread running the callable; CASed during run() */ privatevolatile Thread runner; /** Treiber stack of waiting threads */ privatevolatile WaitNode waiters;
还不明白就看图:
![16e18f5acd01392e7ddd9466bd0e4f4a.png](https://i-blog.csdnimg.cn/blog_migrate/803cca27ad3a5dfef0bb23eee43ad751.jpeg)
![9e76815a1f77c786a5285ec1e8997d92.png](https://i-blog.csdnimg.cn/blog_migrate/573754ec0195bea968368b2c70ac76b0.jpeg)
publicinterface Future { /** *取消任务 *@param mayInterruptIfRunning *是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务 *如果任务正在执行,则返回true *如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,返回true *如果任务已经完成,则无论mayInterruptIfRunning为true还是false,返回false */ boolean cancel(boolean mayInterruptIfRunning); /** *任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true */ boolean isCancelled(); /** *任务是否完成 */ boolean isDone(); /** *通过阻塞获取执行结果 */ T get() throws InterruptedException, ExecutionException; /** *通过阻塞获取执行结果。如果在指定的时间内没有返回,则返回null */ T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}
- Future (1)cancle 可以停止任务的执行 但不一定成功 看返回值true or false (2)get 阻塞获取callable的任务结果,即get阻塞住调用线程,直至计算完成返回结果 (3)isCancelled 是否取消成功 (4)isDone 是否完成
重点说明:
Furture.get()获取执行结果的值,取决于执行的状态,如果任务完成,会立即返回结果,否则一直阻塞直到任务进入完成状态,然后返回结果或者抛出异常。
“运行完成”表示计算的所有可能结束的状态,包含正常结束,由于取消而结束和由于异常而结束。当进入完成状态,他会停止在这个状态上,只要state不处于 NEW 状态,就说明任务已经执行完毕。
FutureTask负责将计算结果从执行任务的线程传递到调用这个线程的线程,而且确保了,传递过程中结果的安全发布
UNSAFE 无锁编程技术,确保了线程的安全性~ 为了保持无锁编程CPU的消耗,所以用状态标记,减少空转的时候CPU的压力
- 任务本尊:callable
- 任务的执行者:runner
- 任务的结果:outcome
- 获取任务的结果:sta