博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程池(二)
阅读量:5100 次
发布时间:2019-06-13

本文共 2419 字,大约阅读时间需要 8 分钟。

Future

在并发编程中,我们经常用到非阻塞的模型,在之前的多线程的三种实现中,不管是继承thread类还是实现runnable接口,都无法保证获取到之前的执行结果。通过实现Callback接口,并用Future可以来接收多线程的执行结果。

Future表示一个可能还没有完成的异步任务的结果,针对这个结果可以添加Callback以便在任务执行成功或失败后作出相应的操作。

接口和类:

Future接口定义了主要的5个接口方法,有RunnableFuture和SchedualFuture继承这个接口,以及CompleteFuture和ForkJoinTask。

RunnableFuture(接口)

这个接口同时继承Future接口和Runnable接口,在成功执行run()方法后,可以通过Future访问执行结果。

FutureTask (实现类)

FutureTask 提供了Future的基本实现,可以实现了启动和取消一个方法,查询这个方法是否已完成。一旦计算完成,这个计算将不能被重启和取消,除非调用runAndReset方法。

  FutureTask能用来包装一个Callable或Runnable对象,因为它实现了Runnable接口,而且它能被传递到Executor进行执行。为了提供单例类,这个类在创建自定义的工作类时提供了protected构造函数。
  通过CAS操作保证状态的变更,通过自旋锁+线程挂起+唤醒的方式来实现阻塞实现类:FutureTask

Future的主要方法

get()方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线程,直到任务执行完毕

get(long timeout,TimeUnit unit)做多等待timeout的时间就会返回结果
cancel(boolean mayInterruptIfRunning)方法可以用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回false.
isDone()方法判断当前方法是否完成
isCancel()方法判断当前方法是否取消

PS

FutureTask 可以直接当做Runnable实现类传给 Thread 执行或者 放在executorService 的submit 中,FutureTask 中的 run() 方法,会判断类型是不是call()方法。AbstractExecutorService 中有submit(call) 方法,

public 
Future
submit(Callable
task) { if (task == null) throw new NullPointerException(); RunnableFuture
ftask = newTaskFor(task);}protected
RunnableFuture
newTaskFor(Callable
callable) { return new FutureTask
(callable);}

Java提供的线程池

FixedThreadPool 

容量固定的线程池。活动状态和线程池容量是有上限的线程池。所有的线程池中,都有一个任务队列。只有核心线程,且数量固定,没有非核心线程。使用的是BlockingQueue<Runnable>作为任务的载体。当线程有空闲的,自动从队列中取出任务执行。

使用场景: 大多数情况下,使用的线程池,首选推荐FixedThreadPool。OS系统和硬件是有线程支持上限。不能随意的无限制提供线程池。

队列默认的容量上限是Integer.MAX_VALUE,基本就是无界队列。

常见的线程池容量: PC - 200。 服务器 - 1000~10000

CachedThreadPool

缓存的线程池。容量不限(Integer.MAX_VALUE)。自动扩容。容量管理策略:如果线程池中的线程数量不满足任务执行,创建新的线程。默认线程空闲60秒,自动销毁。

应用场景: 内部应用或测试应用。 如:电信平台夜间执行数据整理(有把握在短时间内处理完所有工作,且对硬件和软件有足够的信心)。 测试应用,在测试的时候,尝试得到硬件或软件的最高负载量,用于提供FixedThreadPool容量的指导。

SingleThreadExceutor 

单一容量的线程池。

使用场景: 保证任务顺序时使用。如: 游戏大厅中的公共频道聊天。秒杀。

ForkJoinPool

分支合并线程池(mapduce类似的设计思想)。适合用于处理复杂任务。初始化线程容量与CPU核心数相关。

线程池中运行的内容必须是ForkJoinTask的子类型(RecursiveTask,RecursiveAction)。RecursiveTask有返回结果的分支合并任务,RecursiveAction无返回结果的分支合并任务。(Callable/Runnable)compute方法:就是任务的执行逻辑。

ForkJoinPool没有所谓的容量。默认都是1个线程。根据任务自动的分支新的子线程。当子线程任务结束后,自动合并。所谓自动是根据fork和join两个方法实现的。

应用: 主要是做科学计算或天文计算的。数据分析的。

 

转载于:https://www.cnblogs.com/RobertLionLin/p/11536011.html

你可能感兴趣的文章
复杂性渐近阶的重要性
查看>>
js数组创建两种方法
查看>>
IOS自得其乐系列(一)-------------------加载动态图片
查看>>
Function Spec
查看>>
关于我 Jake Lin
查看>>
hue简单介绍
查看>>
现代服务业是什么?
查看>>
java学习笔记十——堆和栈的理解
查看>>
css遮罩蒙版效果 分栏效果
查看>>
rule.xml属性概念
查看>>
JDBC学习笔记
查看>>
css坑了我一下下之line-height
查看>>
python 集合并集
查看>>
CSS样式书写顺序
查看>>
java解决跨域
查看>>
css scroll bug
查看>>
[编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现
查看>>
由一个经典布局问题引发的思考
查看>>
vue 字符串长度控制显示的字数超出显示省略号
查看>>
vim常用命令
查看>>