`
jimichan
  • 浏览: 277811 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Concurrent In Java 6 分享,第二部分 线程池

    博客分类:
  • java
阅读更多

第一部分 集合 http://jimichan.iteye.com/blog/951948

 

第二部分 线程池 http://jimichan.iteye.com/blog/951950

 

第三部分 锁 http://jimichan.iteye.com/blog/951954

 

第四部分 同步辅助类 http://jimichan.iteye.com/blog/951955

Concurrent In Java,第二部分 线程池

 

2011-3-9  延昭 & 陈汝烨 版权所有,特别禁止发布到百度文库

这篇是来自公司内部分享会议是写的总结,有些内容没有表达出来,大家可以来踩,但是需留下原因,以便后续补充。

2. ThreadPool

虽然线程和进程相比是轻量级许多,但是线程的创建成本还是不可忽律,所以就有了线程池化的设计。线程池的创建、管理、回收、任务队列管理、任务分配等细节问题依然负责,没有必要重复发明轮子,concurrent包已经为我们准备了一些优秀线程池的实现。

 

2.1 认识ExecutorService 接口

 

ExecutorService 接口,它能提供的功能就是用来在将来某一个时刻异步地执行一系列任务。虽然简单一句话,但是包含了很多需求点。它的实现至少包含了线程池和任务队列两个方面,其实还包括了任务失败处理策略等。

经常使用submit方法,用来提交任务对象。

 

简单的例子:

 

                ExecutorService es = Executors.newCachedThreadPool();

                

                es.submit(new Runnable(){

                        @Override

                        public void run() {

                                System.out.println("do some thing");                

                        }

                });

 

                es.shutdown();

 

 

 

上面的例子只是完成了提交了一个任务,异步地去执行它。但是有些使用场景更为复杂,比如等待获得异步任务的返回结果,或者最多等上固定的时间。

 

submit 方法返回一个对象,Future。看起来有点别扭,代表将来的对象。其实看一下Future的方法就明白了。

 

 

 

 

 

 

 

 

其实Future对象代表了一个异步任务的结果,可以用来取消任务、查询任务状态,还有通过get方法获得异步任务返回的结果。当调用get方法的时候,当前线程被阻塞直到任务被处理完成或者出现异常。

 

我们可以通过保存Future对象来跟踪查询异步任务的执行情况。

 

显然Runnable接口中定义的 public void run();方法并不能返回结果对象,所以concurrent包提供了Callable接口,它可以被用来返回结果对象。

 

2.2 ThreadPoolExecutor

ThreadPoolExecutor实现了ExecutorService 接口,也是我们最主要使用的实现类。

 

首先非常有必要看一些类的最完整的构造函数

 

ThreadPoolExecutor(int corePoolSize,

   int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue<Runnable> workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandler handler)

 

ThreadPoolExecutor对象中有个poolSize变量表示当前线程池中正在运行的线程数量。

 

注意:这个有关非常重要的关系,常常被误解。poolSize变量和corePoolSize、maximumPoolSize以及workQueue的关系。

 

首先线程池被创建初期,还没有执行任何任务的时候,poolSize等于0;

每次向线程池提交任务的时候,线程池处理过程如下:

 

1. 如果poolSize少于 corePoolSize,则首选添加新的线程,而不进行排队。

2. 如果poolSize等于或多于 corePoolSize,则首选将请求加入队列workQueue,而不添加新的线程。

3. 如果第二步执行失败(队已满),则创建新的线程执行任务,但是如果果poolSize已经达到maximumPoolSize,那么就拒绝该任务。如果处理被拒绝的任务就取决于RejectedExecutionHandler handler的设置了,默认情况下会抛出异常。

系统存在四种任务拒绝策略:

  1. 在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时 RejectedExecutionException
  2. 在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
  3. 在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。
  4. 在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。

 

keepAliveTime活动线程如果空闲一段时间是否可以回收,通常只作用于超出corePoolSize的线程。corePoolSize的线程创建了就不会被回收。但是到java 6 之后增加了public void allowCoreThreadTimeOut(boolean value)法,允许core进程也可以根据keepAliveTime来回收,默认为false。

 

决定线程池特性的还有workQueue的实现类,有三种类SynchronousQueue、LinkedBlockingQueue、ArrayBlockingQueue,分别对应同步队列、无界队列、有界队列。

 

  (摘自JavaDoc)

  1. 类SynchronousQueue,直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务(设置maximumPoolSizes 为Integer.MAX_VALUE)。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
  2. LinkedBlockingQueue,无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
  3. ArrayBlockingQueue,有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。

 

综上:构造参数的设置是互相制约和影响的。只有当你重复了解其相互关系的时候、或有特殊需求的时候,才可以自己构造ThreadPoolExecutor对象,否则可以使用Executores是个工厂类。

 

提示使用线程池是注意处理shutdown,确保你系统关闭的时候主动关闭shutdown。

2.3 ScheduledExecutorService

扩展了ExecutorService接口,提供时间排程的功能。

 

schedule(Callable<V> callable, long delay, TimeUnit unit)

         创建并执行在给定延迟后启用的 ScheduledFuture。

schedule(Runnable command, long delay, TimeUnit unit)

         创建并执行在给定延迟后启用的一次性操作。

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit)

         创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit)

         创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。

 

 

 

schedule方法被用来延迟指定时间来执行某个指定任务。如果你需要周期性重复执行定时任务可以使用scheduleAtFixedRate或者scheduleWithFixedDelay方法,它们不同的是前者以固定频率执行,后者以相对固定频率执行。

 

(感谢wenbois2000 提出原先的错误,我在这里重新描述!对于原先的错误,实在不好意思啊,再次感谢!)

 

不管任务执行耗时是否大于间隔时间,scheduleAtFixedRate和scheduleWithFixedDelay都不会导致同一个任务并发地被执行。唯一不同的是scheduleWithFixedDelay是当前一个任务结束的时刻,开始结算间隔时间,如0秒开始执行第一次任务,任务耗时5秒,任务间隔时间3秒,那么第二次任务执行的时间是在第8秒开始。

 

ScheduledExecutorService的实现类,是ScheduledThreadPoolExecutor。ScheduledThreadPoolExecutor对象包含的线程数量是没有可伸缩性的,只会有固定数量的线程。不过你可以通过其构造函数来设定线程的优先级,来降低定时任务线程的系统占用。

 

 

特别提示:通过ScheduledExecutorService执行的周期任务,如果任务执行过程中抛出了异常,那么过ScheduledExecutorService就会停止执行任务,且也不会再周期地执行该任务了。所以你如果想保住任务都一直被周期执行,那么catch一切可能的异常。

2.4 Executors

Executores是个工厂类,用来生成ThreadPoolExecutor对象,它提供了一些常用的线程池配置方案,满足我们大部分场景。

 

1. newCachedThreadPool

public static ExecutorService newCachedThreadPool() {

       return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                                     60L, TimeUnit.SECONDS,

                                     new SynchronousQueue<Runnable>());

   }

 

分析下出这个线程池配置的工作模式,当没有空闲进程时就新建线程执行,当有空闲线程时就使用空闲线程执行。当线程空闲大60秒时,系统自动回收线程。

 

该线程池非常适合执行短小异步任务时吞吐量非常高,会重复利用CPU的能力。但是如果任务处理IO边界任务,那么会消耗大量线程切换,降低系统吞吐量。所以执行短小的计算任务非常高效,且当没有任务时不会消耗系统资源。

 

注意:线程池中没有变量表示线程是否空闲。那么程序是如何控制的呢?不得不赞叹concurrent实现的非常精巧。当创建出来的线程完成原来的任务后,会调用BlockingQueue的Poll方法,对于SynchronousQueue实现而言会阻塞调用线程,直到另外的线程offer调用。

 

然而ThreadPool在分配任务的时候总是先去尝试调用offer方法,所以就会触发空闲线程再次调用。

 

精妙的是ThreadPoolExecutor的处理逻辑一样,但是用BlockingQueue实现变了就产生不同的行为。

 

2. newFixedThreadPool

 

public static ExecutorService newFixedThreadPool(int nThreads) {

       return new ThreadPoolExecutor(nThreads, nThreads,

                                     0L, TimeUnit.MILLISECONDS,

                                     new LinkedBlockingQueue<Runnable>());

   }

 

创建固定线程数量的线程池,采用无界队列,当有更多任务的时候将被放入工作队列中排队。如果线程池不经常执行任务时,你可以调用allowCoreThreadTimeOut(boolean value)的方法让系统自动回收core的进程,以节约系统资源。

 

3. newSingleThreadExecutor

 

  public static ExecutorService newSingleThreadExecutor() {

       return new FinalizableDelegatedExecutorService

           (new ThreadPoolExecutor(1, 1,

                                   0L, TimeUnit.MILLISECONDS,

                                   new LinkedBlockingQueue<Runnable>()));

   }

只有一个工作线程的线程池。和newFixedThreadPool(1)相比,不同之处有两点:

1. 不可以重新配置newSingleThreadExecutor创建出来的线程池。

2. 当创建出来的线程池对象被GC回收时,会自动调用shutdown方法。

 

4.newScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {

       return new ScheduledThreadPoolExecutor(corePoolSize);

   }

生成一个可以执行时间调度的线程池。其实内部使用无界工作队列,线程数量最多能达到corePoolSize。

 

2.5 ExecutorCompletionService

 

这是个巧妙的设计,内部维护了一已经完成了任务结果队列,通过take方法可以同步地等待一个个结果对象。

详情见http://www.oschina.net/uploads/doc/javase-6-doc-api-zh_CN/java/util/concurrent/ExecutorCompletionService.html

 

 

第三部分 LOCK

http://jimichan.iteye.com/blog/951954

 

 

6
9
分享到:
评论
2 楼 jimichan 2011-03-12  
感谢您提出的问题,对我之前的理解错误表示抱歉,非常感谢你的动手实验
1 楼 wenbois2000 2011-03-12  
关于2.3节,scheduleAtFixedRate 方法不管上一次任务是否执行完毕,都会执行下一次的任务,如果周期为5秒钟,任务执行时间需要8秒钟,那么第5秒钟的时候系统会再次启动一个任务执行,此时系统存在两个任务实例同时运行。如果你的任务执行耗时不确定,而且希望你的任务需要one-by-one不重叠地进行,那么就可以选用者 scheduleWithFixedDelay方法。

我试验的结果是在使用scheduleAtFixedRate 时,任务在上次执行未完成是不会继续开始的,并且在ScheduledExecutorService.scheduleAtFixedRate的Javadoc 上也明确注释了这一点:
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.


下面是完整的JavaDoc
    /**
     * Creates and executes a periodic action that becomes enabled first
     * after the given initial delay, and subsequently with the given
     * period; that is executions will commence after
     * <tt>initialDelay</tt> then <tt>initialDelay+period</tt>, then
     * <tt>initialDelay + 2 * period</tt>, and so on.
     * If any execution of the task
     * encounters an exception, subsequent executions are suppressed.
     * Otherwise, the task will only terminate via cancellation or
     * termination of the executor.  If any execution of this task
     * takes longer than its period, then subsequent executions
     * may start late, but will not concurrently execute.
     *
     * @param command the task to execute
     * @param initialDelay the time to delay first execution
     * @param period the period between successive executions
     * @param unit the time unit of the initialDelay and period parameters
     * @return a ScheduledFuture representing pending completion of
     *         the task, and whose <tt>get()</tt> method will throw an
     *         exception upon cancellation
     * @throws RejectedExecutionException if the task cannot be
     *         scheduled for execution
     * @throws NullPointerException if command is null
     * @throws IllegalArgumentException if period less than or equal to zero
     */
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
						  long initialDelay,
						  long period,
						  TimeUnit unit);

相关推荐

    安卓桌面应用EyeRoom.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

    仿随手记的炫酷饼图.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

    webview重载使用&自定义网址.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

    C语言学习工程和C语言项目.zip

    C语言诞生于美国的贝尔实验室,由丹尼斯·里奇(Dennis MacAlistair Ritchie)以肯尼斯·蓝·汤普森(Kenneth Lane Thompson)设计的B语言为基础发展而来,在它的主体设计完成后,汤普森和里奇用它完全重写了UNIX,且随着UNIX的发展,c语言也得到了不断的完善。为了利于C语言的全面推广,许多专家学者和硬件厂商联合组成了C语言标准委员会,并在之后的1989年,诞生了第一个完备的C标准,简称“C89”,也就是“ANSI C”,截至2020年,最新的C语言标准为2018年6月发布的“C18”。 [5] C语言之所以命名为C,是因为C语言源自Ken Thompson发明的B语言,而B语言则源自BCPL语言。 1967年,剑桥大学的Martin Richards对CPL语言进行了简化,于是产生了BCPL(Basic Combined Programming Language)语言。

    带暂停功能倒计时TimeCountDown盒子适用.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

    Google翻译.txt

    Google翻译.txt

    汽车车灯检测机械臂设计.doc

    汽车车灯检测机械臂设计.doc

    网络购物中心项目源码.rar

    网络购物中心项目源码.rar是一个压缩文件包,包含了一个基于Web技术的电子商务平台的全部源代码和相关资源。这个源码包旨在提供一个功能全面、界面友好的在线购物体验,它集成了商品浏览、搜索、购买、支付以及用户管理等核心电商功能。该项目采用了当下流行的开发框架和编程语言,比如使用HTML5, CSS3, JavaScript, PHP和MySQL数据库等技术,确保了网站的响应速度和跨浏览器兼容性。对于即将毕业的学生或者正在寻找实践项目的课程设计者来说,这个源码包是一个宝贵的资源。它不仅提供了一个实际应用的平台以供学习和研究,还允许用户根据需求进行定制和扩展,如添加新的功能模块或优化现有的代码结构。此外,项目文档详细记录了系统架构、功能实现和部署流程,为初学者提供了清晰的指引。通过分析和修改这份源码,学生可以深化对Web开发的理解,提高编程能力,并且有机会将理论知识转化为实际操作技能。此源码包适合作为计算机科学与技术、软件工程、信息技术等相关专业的毕业设计或课程设计项目,能够帮助学生在完成学业的同时,积累实战经验,增强就业竞争力。无论是作为学习的起点,还是作为未来职业生涯的一个跳板,网络购物

    C语言仓库,存储的是C语言代码.zip

    C语言诞生于美国的贝尔实验室,由丹尼斯·里奇(Dennis MacAlistair Ritchie)以肯尼斯·蓝·汤普森(Kenneth Lane Thompson)设计的B语言为基础发展而来,在它的主体设计完成后,汤普森和里奇用它完全重写了UNIX,且随着UNIX的发展,c语言也得到了不断的完善。为了利于C语言的全面推广,许多专家学者和硬件厂商联合组成了C语言标准委员会,并在之后的1989年,诞生了第一个完备的C标准,简称“C89”,也就是“ANSI C”,截至2020年,最新的C语言标准为2018年6月发布的“C18”。 [5] C语言之所以命名为C,是因为C语言源自Ken Thompson发明的B语言,而B语言则源自BCPL语言。 1967年,剑桥大学的Martin Richards对CPL语言进行了简化,于是产生了BCPL(Basic Combined Programming Language)语言。

    Sora AI Videos的案例站点

    这是Sora AI Videos的案例站点,使用此项目可以帮助你快速构建Sora AI的演示项目。

    2015园林业务齐发展,区域拓展加速(20页).zip

    2015园林业务齐发展,区域拓展加速(20页).zip

    机械臂的物体识别与抓取技术研究.pdf

    机械臂的物体识别与抓取技术研究.pdf

    使用不同的超导间隙模型拟合从穿透深度获得的超流体密度数据matlab代码.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    一个年终抽奖系统,可以根据你需要的去设置

    年终抽奖系统的模型,需要需要特殊定值,可以留言

    埃博拉优化搜索算法matlab代码.zip

    1.版本:matlab2014/2019a/2021a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

    ECommerceCrawlers-master.zip

    实战多种网站、电商数据爬虫。包含:淘宝商品、微信公众号、大众点评、闲鱼、阿里任务、百度贴吧、豆瓣电影、包图网、全景网、豆瓣音乐、某省药监局、搜狐新闻、机器学习文本采集、fofa资产采集、汽车之家️️️

    viewflow视图切换效果.zip

    android 源码学习. 资料部分来源于合法的互联网渠道收集和整理,供大家学习参考与交流。本人不对所涉及的版权问题或内容负法律责任。如有侵权,请通知本人删除。感谢CSDN官方提供大家交流的平台

    可二次开发广州酒店信息管理平台.rar

    广州酒店信息管理平台是一个针对酒店行业设计的综合性信息管理系统,旨在通过现代化的信息技术手段提高酒店运营效率、改善客户体验,并为管理者提供决策支持。该平台以用户友好的界面和强大的数据处理能力为特点,涵盖了客房预订、入住管理、餐饮服务、库存管理、财务报表等多个模块,实现了酒店业务流程的自动化和智能化。作为毕业设计或课程设计项目,这个平台提供了丰富的功能和灵活的二次开发环境。学生可以根据自己的专业知识和兴趣,对现有系统进行深入分析,提出创新改进方案,或者添加新的功能模块。例如,可以通过集成人工智能算法来优化房间分配策略,利用大数据分析技术预测市场趋势,或者开发移动端应用以便客户能够随时随地访问服务。源码文件包中包含了完整的系统架构设计文档、数据库结构、前后端代码以及详细的API文档,使得学生能够快速理解系统运作机制并开始二次开发。此外,平台采用了模块化的设计思想,便于学生按需修改或扩展功能,同时也有助于培养学生的软件工程实践能力和解决实际问题的能力。总之,广州酒店信息管理平台不仅为学生提供了一个实战演练的机会,而且通过实际操作加深了对酒店管理业务和软件开发流程的理解,是一份极具挑战性和实用

    百度翻译.txt

    百度翻译.txt

    python源码python基础

    python源码python基础提取方式是百度网盘分享地址

Global site tag (gtag.js) - Google Analytics