线程池工具类 Executors源代码详解

news2024/9/22 4:35:33


快捷导航

  • 一、提供了什么功能?
    • 源码中的定义:
    • 此类支持以下几种方法:
  • 二、源码中是怎么实现的?
    • 1、创建并返回一个配置了常用设置的`ExecutorService`
      • newFixedThreadPool()
      • newSingleThreadExecutor()
      • newCachedThreadPool()
      • newWorkStealingPool()
    • 2、创建并返回一个`ScheduledExecutorService`
      • newScheduledThreadPool()
      • newSingleThreadScheduledExecutor()
    • 3、创建并返回一个禁用重新配置的`ExecutorService`
      • unconfigurableExecutorService()
      • unconfigurableScheduledExecutorService()
    • 4、创建并返回一个`ThreadFactory`
      • defaultThreadFactory()
      • privilegedThreadFactory()
    • 5、创建并返回一个`Callable`
      • callable()
  • 三、总结:

一、提供了什么功能?

源码中的定义:

该类为ExecutorExecutorServiceScheduledExecutorServiceThreadFactoryCallable类定义了工厂和工具方法。

此类支持以下几种方法:

  • 创建并返回一个配置了常用设置的ExecutorService的方法。
  • 创建并返回一个配置了常用设置的ScheduledExecutorService的方法。
  • 创建并返回一个“包装”的ExecutorService的方法,该方法通过使实现特定的方法不可访问来禁用重新配置。
  • 创建并返回一个将新创建线程设置为已知状态的ThreadFactory的方法。
  • 创建并返回一个Callable的方法,该方法基于其他闭包形式,以便可以在需要Callable的执行方法中使用。

说了这么多的名词,那么这些名词之间的关系是什么?请看下图:
​​​​在这里插入图片描述

二、源码中是怎么实现的?

我们先来看看Executors类的结构:

在这里插入图片描述

1、创建并返回一个配置了常用设置的ExecutorService

newFixedThreadPool()

    /**
     * 创建一个线程池,该线程池重用固定数量的线程,并使用共享的无界队列进行操作。
     * 在任何时候,最多将有 nThreads 个线程处于活动状态以处理任务。
     * 如果在所有线程都处于活动状态时提交了额外的任务,这些任务将等待在队列中,直到有线程可用。
     * 如果在执行过程中任何线程因故障而终止,在关闭之前,如果需要执行后续任务,将会有一个新线程替代它。
     * 线程池中的线程将一直存在,直到显式关闭。 
     *
     * 参数: 
     * nThreads – 线程池中的线程数量 
     *
     * 抛出: 
     * IllegalArgumentException – 如果 nThreads <= 0
     */
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

	/**
     * 使用指定线程工厂创建新线程的重载方法
     *
     * 参数:
     * nThreads – 线程池中的线程数量
     * threadFactory – 创建新线程时使用的工厂
     *
     * 抛出:
     * NullPointerException – 如果threadFactory为null
     * IllegalArgumentException – 如果nThreads <= 0
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

newSingleThreadExecutor()

	/**
     * 从代码上可以看出,该方法和newFixedThreadPool()大同小异,只有两点不同:
     * 1. 线程池核心线程数不同,newFixedThreadPool的核心线程数是方法入参nThreads,而本方法的核心线程数是1。
     * 2. 本方法在new ThreadPoolExecutor()之外加了一层封装new FinalizableDelegatedExecutorService()。
     *    只提供了本类对接口ExecutorService实现的方法的访问接口,目的是防止ThreadPoolExecutor实例在某些情况下	对线程池配置的修改,
     *    例如:使用setCorePoolSize()重新设置线程池核心线程数
     */
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    // 使用指定线程工厂创建新线程的重载方法
    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>(),
                                    threadFactory));
    }

newCachedThreadPool()

	/**
     * 创建一个线程池,该线程池根据需要创建新线程,但会在可用时重用之前构造的线程。
     * 这些线程池通常会提高执行许多短暂异步任务的程序的性能。
     * 调用execute时,如果有可用的线程,将重用之前构造的线程。
     * 如果没有现有线程可用,将创建一个新线程并添加到池中。
     * 未使用超过六十秒的线程将被终止并从缓存中移除。因此,长时间保持空闲的池不会消耗任何资源。
     * 请注意,可以使用ThreadPoolExecutor构造函数创建具有类似属性但不同细节(例如超时参数)的池。
     *
     */
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    // 使用指定线程工厂创建新线程的重载方法
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }    

newWorkStealingPool()

    /**
     * 创建一个线程池,该线程池维护足够的线程以支持给定的并行级别,并可能使用多个队列来减少竞争。
     * 并行级别对应于主动参与或可用于任务处理的最大线程数。
     * 实际线程数量可能会动态增长和缩小。
     * 工作窃取池不保证提交任务的执行顺序。 
     *
     * 参数: 
     * parallelism – 目标并行级别 
     *
     * 抛出: 
     * IllegalArgumentException – 如果 parallelism <= 0 
     */
    public static ExecutorService newWorkStealingPool(int parallelism) {
        return new ForkJoinPool
            (parallelism,
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }     
    // 创建一个工作窃取线程池,使用所有可用处理器作为其目标并行级别。
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

2、创建并返回一个ScheduledExecutorService

newScheduledThreadPool()

	/**
     * 创建一个可以在给定延迟后运行或定期执行的线程池。 
     *
     * 参数: 
     * corePoolSize – 即使线程处于空闲状态,也要保持在池中的线程数量 
     *
     * 抛出: 
     * IllegalArgumentException – 如果 corePoolSize < 0
     */
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    // 使用指定线程工厂创建新线程的重载方法
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }

newSingleThreadScheduledExecutor()

	// 返回一个类似newScheduledThreadPool(1)的单线程执行器,在任何情况下线程数量都不可更改
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
	// 使用指定线程工厂创建新线程的重载方法
    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

3、创建并返回一个禁用重新配置的ExecutorService

unconfigurableExecutorService()

	// 和newSingleThreadExecutor()、newSingleThreadScheduledExecutor()类似的套路
	// 添加一个包装类,屏蔽返回的线程池对象对配置的修改
    public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
        if (executor == null)
            throw new NullPointerException();
        return new DelegatedExecutorService(executor);
    }

unconfigurableScheduledExecutorService()

	// 和unconfigurableExecutorService同样的套路
    public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
        if (executor == null)
            throw new NullPointerException();
        return new DelegatedScheduledExecutorService(executor);
    }

4、创建并返回一个ThreadFactory

defaultThreadFactory()

    public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
    }
    
    // 静态内部类DefaultThreadFactory
    static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

privilegedThreadFactory()

    
    public static ThreadFactory privilegedThreadFactory() {
        return new PrivilegedThreadFactory();
    }
    
    /**
     * Thread factory capturing access control context and class loader
     */
    static class PrivilegedThreadFactory extends DefaultThreadFactory {
        private final AccessControlContext acc;
        private final ClassLoader ccl;

        PrivilegedThreadFactory() {
            super();
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                // Calls to getContextClassLoader from this class
                // never trigger a security check, but we check
                // whether our callers have this permission anyways.
                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);

                // Fail fast
                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
            }
            this.acc = AccessController.getContext();
            this.ccl = Thread.currentThread().getContextClassLoader();
        }

        public Thread newThread(final Runnable r) {
            return super.newThread(new Runnable() {
                public void run() {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            Thread.currentThread().setContextClassLoader(ccl);
                            r.run();
                            return null;
                        }
                    }, acc);
                }
            });
        }
    }

5、创建并返回一个Callable

callable()


    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }

    public static Callable<Object> callable(Runnable task) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<Object>(task, null);
    }

    public static Callable<Object> callable(final PrivilegedAction<?> action) {
        if (action == null)
            throw new NullPointerException();
        return new Callable<Object>() {
            public Object call() { return action.run(); }};
    }

    public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
        if (action == null)
            throw new NullPointerException();
        return new Callable<Object>() {
            public Object call() throws Exception { return action.run(); }};
    }

    public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
        if (callable == null)
            throw new NullPointerException();
        return new PrivilegedCallable<T>(callable);
    }

    public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
        if (callable == null)
            throw new NullPointerException();
        return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
    }

三、总结:

  1. 通过对以上源码的分析,可以发现虽然Executors工具类提供了很多快速创建线程池的方法,但归根结底还是对ThreadPoolExecutor、ScheduledThreadPoolExecutor的封装。我们可以很容易的根据自己的项目情况去自定义,这样的创建的线程池才是最符合业务场景的。
  2. 在Executors提供的快速创建线程池的方法中,若有贴合使用业务场景的,可以直接使用,这样可以提高开发效率,避免重复造轮子。
  3. Executors提供了从Runable到Callable的转换,这可能在需要线程提供返回值的时候是有用的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974154.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学习C#调用LazyCaptcha模块生成验证码的基本用法

LazyCaptcha是仿EasyCaptcha和SimpleCaptcha的.net开源图形验证码模块&#xff0c;其支持生成验证码及对应的静态图或动态图&#xff0c;还支持在图形中增加气泡、干扰线等噪音以提升图片自动识别难度。LazyCaptcha既能在B/S程序中使用&#xff08;本文的原由即Admin.NET中使用…

【数据结构初阶】深度理解 “栈” (附源码)

hello&#xff0c;又见面了&#xff01; 目录 1. 栈的概念与结构 2、栈的实现 Stack.h Stack.c test.c 3、习题 正文开始—— 1. 栈的概念与结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端…

小试牛刀-Telebot区块链游戏机器人(TS升级)

目录 1.编写目的 2.为什么使用TypeScript实现? 3.实现功能 3.1 AI图片生成 3.2 签到 3.3 邀请 3.4 WalletConnect连接 4.功能实现详解 4.1 AI图片生成 4.2 签到 4.3 邀请 4.4 WalletConnect连接 5.功能截图 ​6.问题整理 Welcome to Code Blocks blog 本篇文章主…

塑造美好心灵,激发创造活力|第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展开展

第三届瓷艺中华“陶溪川杯”儿童青少年陶瓷作品展 展览现场 由中央美术学院、景德镇陶瓷大学、景德镇陶文旅控股集团共同主办&#xff0c;由中国非物质文化遗产保护协会陶瓷分会、中国文化艺术发展促进会陶瓷专业委员会、中央美术学院陶瓷艺术研究院、中央美术学院少儿美术教…

无人机无刷电机技术详解及选型

1. 技术原理 无人机无刷电机&#xff08;Brushless DC Motor, BLDC&#xff09;是现代无人机动力系统的核心部件&#xff0c;其工作原理基于电磁感应和换向技术&#xff0c;实现了无需物理接触即可持续旋转的高效率动力输出。与传统有刷电机相比&#xff0c;无刷电机通过电子换…

你好! Git——如何进行多人协作

多人协作&#xff08;5&#xff09; 一、标签管理二、多人协作2.1 场景一&#xff08;这种方式不常见&#xff09;2.2 场景二&#xff08;常见&#xff09; 一、标签管理 标签 tag &#xff0c;可以简单的理解为是对某次 commit 的⼀个标识&#xff0c;相当于起了⼀个别名。 …

【给嵌入式新人的几条建议(共勉):三-C语言基础怎么补?】

给嵌入式新人的几条建议&#xff08;共勉&#xff09;&#xff1a;三-C语言基础怎么补&#xff1f; 前言1、先回答一个问题&#xff0c;对C语言的害怕到底在哪&#xff1f;&#xff08;纠正认知&#xff09;2、C语言基础&#xff0c;要补全部吗&#xff1f;No2.1 先看下自己属于…

深耕编程语言18年,对话 Rust、TypeScript、Nushell 核心贡献者 Sophia Turner | Open AGI Forum

作者 | Annie Xu 采访 | 卢威 责编 | Echo Tang 出品丨GOSIM 开源创新汇 编程语言的种类令人眼花缭乱&#xff0c;但成功的、常用的编程语言却是凤毛麟角。在深耕编程语言研发 18 年的 Sophia June Turner 看来&#xff0c;编程语言成功的关键在于其研发团队的透明度和机制建…

Azure OpenAI Embeddings vs OpenAI Embeddings

题意&#xff1a;Azure OpenAI 嵌入与 OpenAI 嵌入的比较 问题背景&#xff1a; Is anyone getting different results from Azure OpenAI embeddings deployment using text-embedding-ada-002 than the ones from OpenAI? Same text, same model, and the results are cons…

Learning vtkjs之Calculator

过滤器 公式计算器 Calculator 介绍 The Calculator filter is a fast way to add derived data arrays to a dataset. These arrays can be defined over points, cells, or just field data that is “uniform” across the dataset (i.e., constant over all of space). Va…

【小尘送书-第十六期】码农职场:IT人求职就业手册

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…

【JVM】垃圾回收机制、算法和垃圾回收器

什么是垃圾回收机制 为了让程序员更加专注于代码的实现&#xff0c;而不用过多的考虑内存释放的问题&#xff0c;所以在Java语言中&#xff0c;有了自动的垃圾回收机制&#xff0c;也是我们常常提及的GC(Garbage Collection) 有了这个垃圾回收机制之后&#xff0c;程序员只需…

华为路由常见 LSA 类型的产生及作用域和字段详细解读

华为路由常见 LSA 类型的产生及作用域 类型名称描述1路由器 LSA&#xff08;Router LSA&#xff09;每个设备都会产生&#xff0c;描述了设备的链路状态和开销。该 LSA 只能在接口所属的区域内泛洪2网络 LSA&#xff08;Network LSA&#xff09;由 DR 产生&#xff0c;描述该 …

在cPanelWHM中如何重置 MySQL 用户帐户密码

更改MySQL用户账户密码非常简单。服务器管理员可以在WHM中编辑任何MySQL用户的帐户。cPanel用户可以编辑其帐户管理的数据库的密码。 在WHM中更改MySQL用户帐户密码 打开WHM&#xff0c;在侧边菜单中的SQL服务下选择“Change MySQLUser Password”。Hostease的服务器产品提供稳…

NeRF学习——复现训练中的问题记录

代码复现的框架是基于&#xff1a;pengsida 的 Learning NeRF 希望各位可以通过学习 NeRF-Pytorch 的源码来自己复现一下试试看&#xff01; 文章目录 1 Windows bug1.1 DataLoader 的多进程 pickle1.2 imageio 输出图片1.3 I/O 2 训练问题2.1 Evaluate 显存爆炸2.2 尝试一2.…

基于VScode和C++实现Protobuf数据格式的通信

目录 1. Protobuf 概述1.1 定义1.2Protobuf的优势 2. Protobuf 语法3、序列号和反序列化3.1 .pb.h 头文件3.2 序列化3.3 反序列化 4、测试用例 Protobuf详细讲解链接 1. Protobuf 概述 1.1 定义 protobuf也叫protocol buffer是google 的一种数据交换的格式&#xff0c;它独立…

递归题解集

目录 递归&#xff1a; 一、汉诺塔问题 1.题目链接&#xff1a;面试题 08.06. 汉诺塔问题 2.题目描述&#xff1a; 3.解法&#xff1a;&#xff08;递归&#xff09; &#x1f335;算法思路&#xff1a; &#x1f335;算法流程&#xff1a; &#x1f335;算法代码&…

掌握SEO站外推广优化的五大绝招

对于网站运营者和数字营销人员来说&#xff0c;SEO站外推广是提升网站流量和排名的重要手段。以下是五个有效的SEO站外推广优化方法&#xff0c;希望对大家有所帮助。 1. 高质量的外链建设 高质量的外部链接&#xff08;Backlinks&#xff09;是搜索引擎排名的重要因素之一。…

Openboxes开发环境配置及本地化、API测试

目录 Openboxes简介 开发环境配置及启动 更新中文多语言配置 API测试 Openboxes简介 Openboxes是一款开源的仓库管理软件&#xff0c;提供了库存管理、采购管理、销售管理等功能&#xff0c;可以帮助用户高效地管理仓库及库存。并提供了丰富的API接口。系统基于java8 和Gr…