前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java线程池

java线程池

作者头像
良辰美景TT
发布2018-09-11 14:32:16
8470
发布2018-09-11 14:32:16
举报
文章被收录于专栏:java、Spring、技术分享

线程池能够帮助我们提高系统资源利用效率,并简化线程管理。通过并发包下的Executors(不是Executor)可以方便的创建如下几类线程池。分别为:

  • newCachedThreadPool(),用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列
  • newFixedThreadPool(int nThreads),重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动线程数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads
  • newSingleThreadExecutor(),它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目。
  • newSingleThreadScheduledExecutor() 和 newScheduledThreadPool(int corePoolSize),创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。
  • newWorkStealingPool(int parallelism),Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序
ThreadPoolExecutor源码分析

下面来分析一下ThreadPoolExecutor是如何实现线程池的。首先看看线程池框架图:

线程池框架

应用与线程池的交互和线程池的内部工作过程如下图所示:

应用与线程池的交互和线程池的内部工作过程

其中有几个重要的概念:

  • 工作队列负责存储用户提交的各个任务,这个工作队列,可以是容量为 0 的 SynchronousQueue(使用 newCachedThreadPool),也可以是像固定大小线程池(newFixedThreadPool)那样使用 LinkedBlockingQueue
  • 内部的“线程池”,这是指保持工作线程的集合(是一个HashSet<Worker>),线程池需要在运行过程中管理线程创建、销毁。线程池的工作线程被抽象为静态内部类 Worker,基于AQS实现。
  • ThreadFactory 提供上面所需要的创建线程逻辑。
  • 如果任务提交时被拒绝,比如线程池已经处于 SHUTDOWN 状态或者队列已经满了,需要为其提供处理逻辑,Java 标准库提供了类似ThreadPoolExecutor.AbortPolicy等默认实现,也可以按照实际需求自定义。

理解了上面的几个概念,再看ThreadPoolExecutor的构造方法就能够很容易的理解各参数的含义了,源码截图如下:

ThreadPoolExecutor构造方法

execute方法的源码如下:

代码语言:javascript
复制
    public void execute(Runnable command) {
//验证传入参数的合法性
        if (command == null)
            throw new NullPointerException();
// 检查工作线程数目,低于 corePoolSize 则添加线程(这里的线程给Worker进行包装)
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
//线程没有被shutdown,则将command加入到任务队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
// 再次进行防御性检查
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
// 尝试添加一个 worker,如果失败以为着已经饱和或者被shutdown了
        else if (!addWorker(command, false))
            reject(command);
    }

线程状态流转图如下所示:

线程状态流转图

线程池大小的选择原则
  • 如果是CPU密集型的业务,增加线程数并不能够提高计算能力,反而会因为线程的上下文切换使计算变慢,所以线程数设计成跟CPU的核心数一样是合理的。
  • 如果是等待任务较多的业务,可以通过如下公式进行计算: 线程数 = CPU 核数 × (1 + 平均等待时间 / 平均工作时间)
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.08.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ThreadPoolExecutor源码分析
  • 线程池大小的选择原则
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档