资讯专栏INFORMATION COLUMN

java线程池的基本使用

sf190404 / 583人阅读

摘要:此外,有两个常用的关闭线程池的方法第一个方法将启动一次顺序关闭,有任务在执行,则等待执行完成,但不接受新的任务第二个方法将取消所有未开始的任务并且试图中断正在执行的任务,返回从未开始执行的任务的列表。

四种线程池

Executors中提供了四种线程池:

newCachedThreadPool 可缓存线程池,对于每个线程,如果有空闲线程可用,立即让它执行,如果没有,则创建一个新线程

newFixedThreadPool 具有固定大小的线程池,如果任务数大于空闲的线程数,则把它们放进队列中等待

newSingleThreadPool大小为1的线程池,任务一个接着一个完成

newScheduledThreadPool 定长线程池,可控制线程最大并发数,支持定时及周期性任务执行,用来代替Timer

基本方法

在上文http://segmentfault.com/a/1190000003091174 中说到了callable不能直接被Thread运行,但却能被线程池运行,ExecutorService提供了几种方法运行一个任务:

Future submit(Callable task);
Future submit(Runnable task, T result);
Future submit(Runnable task);

第一个方法可以直接提交一个Callable任务,返回一个包含结果的Future,第二个方法会返回指定的result对象,第三个方法返回一个Future,可以使用这样的对象来调用isDone,cancel,isCancelled,但是在get的时候返回null。

此外,有两个常用的关闭线程池的方法:

void shutdown();
List shutdownNow()

第一个方法将启动一次顺序关闭,有任务在执行,则等待执行完成,但不接受新的任务;
第二个方法将取消所有未开始的任务并且试图中断正在执行的任务,返回从未开始执行的任务的列表。无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。例如,通过 Thread.interrupt() 来取消典型的实现,所以任何任务无法响应中断都可能永远无法终止。

控制一组任务

ExecutorService提供了invokeAnyinvokeAll方法,它们是批量执行的最常用形式,它们执行任务collection,然后等待至少一个,或全部任务完成

/**
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。返回列表的所有元素的 Future.isDone() 为 true。
注意,可以正常地或通过抛出异常来终止已完成任务。
**/
 List> invokeAll(Collection> tasks)
                          throws InterruptedException
/**
执行给定的任务,如果其中一个任务的结果。一旦正常或异常返回后,则取消尚未完成的任务。
**/                          
 T invokeAny(Collection> tasks)
            throws InterruptedException,
                   ExecutionException                          

invokeAny方法提交所有任务到一个Callable对象的集合中,并且返回某个已经完成了的任务的结果,返回的任务是不确定的。invokeAll方法则返回所有任务的结果,可以这样来对结果进行处理:

List> tasks=...
List> results = executor.invokeAll(tasks);
for(Future result : results){
    process(result.get());
}
...

这样处理的一个弊端是,如果第一个任务花费了很长时间,则不得不等待。在某些情况下,可能只需要一个任务出了结果就可以中止所有任务,这样就得不偿失。将结果按照可获得的顺序保存起来可能更好,这时需要用到ExecutorCompletionService来进行排列:

ExecutorCompletionService service = new ExecutorCompletionService(executor);
for(Callable task:tasks){
    service.submit(task);
}

for(int i = 0;i < task.size();i++){
    process(service.take().get());
}
...

其中,take()方法会移除下一个已经完成的结果(Future),如果没有可用结果则阻塞

使用小结

在使用线程池时,大多应该按照以下步骤:

调用Executors类中的静态方法newCachedThreadPoolnewFixedThreadPool创建线程池;

调用submit提交RunnableCallable任务;

如果想取消一个任务,或者提交了Callable对象,那就要保存好返回的Future对象;

当不再提交任务时,调用shutdown

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64436.html

相关文章

  • Java线程笔记(三):线程

    摘要:类则扮演线程池工厂角色,通过可以取得一个具有特定功能的线程池。返回一个可根据实际情况调整线程数量的线程池,线程数量不确定,若有空闲,则会有限复用线程。所有线程在当前任务执行完后,将返回线程池待复用。 前言 多线程的软件设计方案确实可以最大限度地发挥现代多核处理器的计算能力,提高生产系列的吞吐量和性能。但是,若不加控制和管理的随意使用线程,对系统的性能反而会产生不利的影响。最容易想到的后...

    琛h。 评论0 收藏0
  • Java线程(2):使用线程池 ThreadPoolExecutor

    摘要:本文只介绍中线程池的基本使用,不会过多的涉及到线程池的原理。可缓存线程的线程池创建一个可缓存线程的线程池。首先是从接口继承到的方法使用该方法即将一个任务交给线程池去执行。方法方法的作用是向线程池发送关闭的指令。 首先,我们为什么需要线程池?让我们先来了解下什么是 对象池 技术。某些对象(比如线程,数据库连接等),它们创建的代价是非常大的 —— 相比于一般对象,它们创建消耗的时间和内存都...

    darry 评论0 收藏0
  • Java线程池从使用到阅读源码(3/10)

    摘要:最后,我们会通过对源代码的剖析深入了解线程池的运行过程和具体设计,真正达到知其然而知其所以然的水平。创建线程池既然线程池是一个类,那么最直接的使用方法一定是一个类的对象,例如。单线程线程池单线程线程 我们一般不会选择直接使用线程类Thread进行多线程编程,而是使用更方便的线程池来进行任务的调度和管理。线程池就像共享单车,我们只要在我们有需要的时候去获取就可以了。甚至可以说线程池更棒,...

    468122151 评论0 收藏0
  • Java中的线程

    摘要:中的线程池运用场景非常广泛,几乎所有的一步或者并发执行程序都可以使用。代码中如果执行了方法,线程池会提前创建并启动所有核心线程。线程池最大数量线程池允许创建的线程最大数量。被称为是可重用固定线程数的线程池。 Java中的线程池运用场景非常广泛,几乎所有的一步或者并发执行程序都可以使用。那么线程池有什么好处呢,以及他的实现原理是怎么样的呢? 使用线程池的好处 在开发过程中,合理的使用线程...

    tomato 评论0 收藏0
  • 马士兵MCA架构师Java互联网架构师

    摘要:如果是这样,你一定要拿出个小时的时间,参加一次马士兵老师的多线程与高并发训练营。横扫一切关于多线程的问题,吊打所有敢于提问并发问题的面试官。 如果你平时只有CRUD的经验,从来不会了解多线程与高并发,相信你一定一头雾水。如果是这样,你一定要拿出4个小时的时间,参加一次马士兵老师的《多线程与高并发》训练营。让骨灰级扫地神僧马...

    dantezhao 评论0 收藏0

发表评论

0条评论

sf190404

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<