0.9.1、自定义线程池

描述

自定义线程池可以帮助我们掌握更多的线程自主权,方便于后期代码的维护和问题的排查。

应用知识点
  • 自定义线程池
  • 线程工厂
  • 线程池关闭
  • 线程池最佳线程数
在《Java Concurrency in Practice》一书中,给出了估算线程池大小的公式:
  Nthreads = Ncpu x Ucpu x (1 + W/C),其中
  Ncpu = CPU核心数
  Ucpu = CPU使用率,0~1
  W/C = 等待时间与计算时间的比率
public static void main(String [] args){
		# 获取 CPU 数目
        int CPU_numbers = Runtime.getRuntime().availableProcessors();
        System.out.println("CPU_numbers="+CPU_numbers);
    }
线程池阻塞队列
名称底层实现处理顺讯添加顺序容量文档
ArrayBlockingQueue数组FIFO新任务添加到队尾容量可在初始化时指定
LinekdBlockingQueue链表FIFO新任务添加到队尾默认 Integer.MAX_VALUE
PriorityBlockingQueue数组任务线程优先级内部按照平衡二叉堆理论上无界,默认为11,但是数组长度不能大于 Integer.MAX_VALUE - 8,否则主动报 OutOfMemoryErrorhttps://www.jianshu.com/p/3ab47f9bdfe8
DelayQueue数组按照过期时间无界
SynchronousQueue结点每一个put操作必须等待take操作,支持公平锁和非公平锁无界
LinkedBlockingDeque链表(双向)FIFO/FILO默认 Integer.MAX_VALUE
LinkedTransferQueue链表FIFO无界,消费者预占模式,如果存在预占,新元素不入队,直接被消费者消费
向阻塞队列添加元素的方法 add\offer\put 的区别
类型说明方法定义
BlockingQueue.add要没在队尾添加成功,如果队列已满,则直接抛出 IllegalStateException 异常boolean add(E e)
BlockingQueue.offer要没在队尾添加成功,如果队列已满,则直接返回 falseboolean offer(E e)
BlockingQueue.put要没在队尾添加成功,如果队列已满,等待直到可以获取一个元素void put(E e) throws InterruptedException
从阻塞队列获取元素的方法 take\poll\remove

poll 支持等待一段时间

类型说明方法定义
BlockingQueue.take从队首获取一个元素,如果没有元素则等待E take() throws InterruptedException
Queue.poll返回队首的一个元素,如果没有则返回nullE poll()
BlockingQueue.poll返回队首的一个元素,如果没有则等待一段时间,如果仍没有获取,则返回nullE poll(long timeout, TimeUnit unit) throws InterruptedException
BlockingQueue.remove(Object o)从队列中移除指定对象,如果成功返回true,如果不存在则返回 falseboolean remove(Object o);
线程池拒绝策略

四种策略

ThreadPoolExecutor.AbortPolicy()中止待被执行的线程,抛出 RejectedExecutionException默认饱和策略
ThreadPoolExecutor.CallerRunsPolicy()不会占用线程池的线程,调用线程池的主线程参与该线程执行-
ThreadPoolExecutor.DiscardOldestPolicy()抛弃待最先被执行的任务,优先级越高越会被先抛弃-
DiscardPolicy()直接抛弃任务,不会抛出异常-

默认策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

核心线程数如何确保不被销毁

https://blog.youkuaiyun.com/smile_from_2015/article/details/105259789

代码
Maven
<dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>29.0-jre</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.72</version>
    </dependency>
自定义 Java 线程池
  • 支持 自定义线程工厂 namedThreadFactory
  • 支持获取线程执行结果 newFutureTask
import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.*;

/**
 * @Title: 线程池测试
 * @Description: 线程池测试
 * @Author: wujie
 * @Version: v1.0
 * @Date:2020-06-10
 * @Updatedby:
 */
public class ThreadTest {
    private final static int CORE_POOL_SIZE = 10;
    private final static int MAX_I_MUM_POOL_SIZE = 10;
    private final static long KEEP_ALIVE_TIME = 0L;
    private final static int WORKQUEUE_SIZE = 1024;
    /**
     * 自定义线程名称,方便的出错的时候溯源
     */
    private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("center-pool-%d").build();
    private static ExecutorService threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_I_MUM_POOL_SIZE, KEEP_ALIVE_TIME,
            TimeUnit.MILLISECONDS, new LinkedBlockingDeque(WORKQUEUE_SIZE), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

//使用lamada表达式实现接口作为匿名内部类
    private static ExecutorService threadPool2 = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_I_MUM_POOL_SIZE, KEEP_ALIVE_TIME,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingDeque(WORKQUEUE_SIZE),
            (runnable)->{Thread t= new Thread(runnable)
                    t.setName("center-pool-%d");
            return t;}
            , new ThreadPoolExecutor.AbortPolicy());


    /**
     * 获取线程池
     */
    public static ExecutorService getThreadPool() {
        return threadPool;
    }

    /**
     * 获取线程池工厂
     */
    public static ThreadFactory getThreadFactory(){
        return namedThreadFactory;
    }

    /**
     * 执行任务
     * @param r
     */
    public static void newTask(Runnable r) {
        threadPool.execute(r);
    }

    /**
     * 执行任务-需要获取线程执行结果
     * @param r
     */
    public static Future newFutureTask(Runnable r) {
        return threadPool.submit(r);
    }

    /**
     * 关闭线程池(如有在执行任务则等待)
     */
    public static void destroyExecutorService(){
        System.out.println("关闭线程池");
        if(!threadPool.isShutdown()){
            threadPool.shutdown();
        }
    }

    /**
     * 立即关闭线程池
     */
    public static void destroyNowExecutorService(){
        System.out.println("立即关闭线程池");
        if(!threadPool.isShutdown()){
            threadPool.shutdownNow();
        }
    }

    /**
     * 线程池是否关闭
     * @return
     */
    public static boolean isExecutorServiceDownNow(){
        return threadPool.isShutdown();
    }
}
自定义线程池的简单使用
自定义线程池结合 Thread
public class ThreadUseTest {

    private static class MyThread extends Thread{
        @Override
        public void run() {
            super.run();
            System.out.println("自定义线程池,可以通过构造参数传参");
        }
    }

    public static void main(String [] args){
        ThreadTest.newTask(ThreadTest.getThreadFactory().newThread(new MyThread()));
        ThreadTest.destroyExecutorService();
    }
}
自定义线程池结合 Runnable
public class ThreadUseTest {

    private static class MyRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("自定义线程池,可以通过构造参数传参");
        }
    }

    public static void main(String [] args){
        ThreadTest.newTask(ThreadTest.getThreadFactory().newThread(new MyRunnable()));
        ThreadTest.destroyExecutorService();
    }
}

自定义线程池结合 Future (需要获取执行结果)

Futuretask 学习(如果了解 Future 可以直接看 “使用线程池执行 FutureTask”小标题,否则建议阅读全文)

参考资料

[1]、https://www.cnblogs.com/xhq1024/p/12125290.html

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -XX:TieredStopAtLevel=1 -noverify -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-javaagent:D:\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=65356:D:\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\biili\新建文件夹\springboot-alidruid-master\target\classes;D:\zuoye\com\alibaba\druid-spring-boot-starter\1.1.23\druid-spring-boot-starter-1.1.23.jar;D:\zuoye\com\alibaba\druid\1.1.23\druid-1.1.23.jar;D:\zuoye\org\slf4j\slf4j-api\1.7.26\slf4j-api-1.7.26.jar;D:\zuoye\org\springframework\boot\spring-boot-autoconfigure\2.1.4.RELEASE\spring-boot-autoconfigure-2.1.4.RELEASE.jar;D:\zuoye\org\springframework\boot\spring-boot\2.1.4.RELEASE\spring-boot-2.1.4.RELEASE.jar;D:\zuoye\mysql\mysql-connector-java\8.0.15\mysql-connector-java-8.0.15.jar;D:\zuoye\org\projectlombok\lombok\1.16.20\lombok-1.16.20.jar;D:\zuoye\com\alibaba\fastjson\1.2.83\fastjson-1.2.83.jar;D:\zuoye\org\springframework\boot\spring-boot-starter-web\2.1.4.RELEASE\spring-boot-starter-web-2.1.4.RELEASE.jar;D:\zuoye\org\springframework\boot\spring-boot-starter\2.1.4.RELEASE\spring-boot-starter-2.1.4.RELEASE.jar;D:\zuoye\org\springframework\boot\spring-boot-starter-logging\2.1.4.RELEASE\spring-boot-starter-logging-2.1.4.RELEASE.jar;D:\zuoye\ch\qos\logback\logback-classic\1.2.3\logback-classic-1.2.3.jar;D:\zuoye\ch\qos\logback\logback-core\1.2.3\logback-core-1.2.3.jar;D:\zuoye\org\apache\logging\log4j\log4j-to-slf4j\2.11.2\log4j-to-slf4j-2.11.2.jar;D:\zuoye\org\apache\logging\log4j\log4j-api\2.11.2\log4j-api-2.11.2.jar;D:\zuoye\org\slf4j\jul-to-slf4j\1.7.26\jul-to-slf4j-1.7.26.jar;D:\zuoye\javax\annotation\javax.annotation-api\1.3.2\javax.annotation-api-1.3.2.jar;D:\zuoye\org\yaml\snakeyaml\1.23\snakeyaml-1.23.jar;D:\zuoye\org\springframework\boot\spring-boot-starter-json\2.1.4.RELEASE\spring-boot-starter-json-2.1.4.RELEASE.jar;D:\zuoye\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.9.8\jackson-datatype-jdk8-2.9.8.jar;D:\zuoye\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.9.8\jackson-datatype-jsr310-2.9.8.jar;D:\zuoye\com\fasterxml\jackson\module\jackson-module-parameter-names\2.9.8\jackson-module-parameter-names-2.9.8.jar;D:\zuoye\org\springframework\boot\spring-boot-starter-tomcat\2.1.4.RELEASE\spring-boot-starter-tomcat-2.1.4.RELEASE.jar;D:\zuoye\org\apache\tomcat\embed\tomcat-embed-core\9.0.17\tomcat-embed-core-9.0.17.jar;D:\zuoye\org\apache\tomcat\embed\tomcat-embed-el\9.0.17\tomcat-embed-el-9.0.17.jar;D:\zuoye\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.17\tomcat-embed-websocket-9.0.17.jar;D:\zuoye\org\hibernate\validator\hibernate-validator\6.0.16.Final\hibernate-validator-6.0.16.Final.jar;D:\zuoye\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;D:\zuoye\org\jboss\logging\jboss-logging\3.3.2.Final\jboss-logging-3.3.2.Final.jar;D:\zuoye\com\fasterxml\classmate\1.4.0\classmate-1.4.0.jar;D:\zuoye\org\springframework\spring-web\5.1.6.RELEASE\spring-web-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\spring-beans\5.1.6.RELEASE\spring-beans-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\spring-webmvc\5.1.6.RELEASE\spring-webmvc-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\spring-context\5.1.6.RELEASE\spring-context-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\spring-expression\5.1.6.RELEASE\spring-expression-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\boot\spring-boot-starter-aop\2.1.4.RELEASE\spring-boot-starter-aop-2.1.4.RELEASE.jar;D:\zuoye\org\springframework\spring-aop\5.1.6.RELEASE\spring-aop-5.1.6.RELEASE.jar;D:\zuoye\org\aspectj\aspectjweaver\1.9.2\aspectjweaver-1.9.2.jar;D:\zuoye\org\springframework\spring-core\5.1.6.RELEASE\spring-core-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\spring-jcl\5.1.6.RELEASE\spring-jcl-5.1.6.RELEASE.jar;D:\zuoye\com\baomidou\mybatis-plus-boot-starter\3.4.0\mybatis-plus-boot-starter-3.4.0.jar;D:\zuoye\com\baomidou\mybatis-plus\3.4.0\mybatis-plus-3.4.0.jar;D:\zuoye\com\baomidou\mybatis-plus-extension\3.4.0\mybatis-plus-extension-3.4.0.jar;D:\zuoye\com\baomidou\mybatis-plus-core\3.4.0\mybatis-plus-core-3.4.0.jar;D:\zuoye\com\baomidou\mybatis-plus-annotation\3.4.0\mybatis-plus-annotation-3.4.0.jar;D:\zuoye\com\github\jsqlparser\jsqlparser\3.2\jsqlparser-3.2.jar;D:\zuoye\org\mybatis\mybatis\3.5.5\mybatis-3.5.5.jar;D:\zuoye\org\mybatis\mybatis-spring\2.0.5\mybatis-spring-2.0.5.jar;D:\zuoye\org\springframework\boot\spring-boot-starter-jdbc\2.1.4.RELEASE\spring-boot-starter-jdbc-2.1.4.RELEASE.jar;D:\zuoye\org\springframework\spring-jdbc\5.1.6.RELEASE\spring-jdbc-5.1.6.RELEASE.jar;D:\zuoye\org\springframework\spring-tx\5.1.6.RELEASE\spring-tx-5.1.6.RELEASE.jar;D:\zuoye\com\alibaba\transmittable-thread-local\2.12.6\transmittable-thread-local-2.12.6.jar;D:\zuoye\cn\hutool\hutool-all\5.8.29\hutool-all-5.8.29.jar;D:\zuoye\org\apache\commons\commons-lang3\3.8.1\commons-lang3-3.8.1.jar;D:\zuoye\io\jsonwebtoken\jjwt\0.9.1\jjwt-0.9.1.jar;D:\zuoye\com\fasterxml\jackson\core\jackson-databind\2.9.8\jackson-databind-2.9.8.jar;D:\zuoye\com\fasterxml\jackson\core\jackson-annotations\2.9.0\jackson-annotations-2.9.0.jar;D:\zuoye\com\fasterxml\jackson\core\jackson-core\2.9.8\jackson-core-2.9.8.jar;D:\zuoye\com\github\xiaoymin\knife4j-openapi3-spring-boot-starter\4.5.0\knife4j-openapi3-spring-boot-starter-4.5.0.jar;D:\zuoye\com\github\xiaoymin\knife4j-core\4.5.0\knife4j-core-4.5.0.jar;D:\zuoye\com\github\xiaoymin\knife4j-openapi3-ui\4.5.0\knife4j-openapi3-ui-4.5.0.jar;D:\zuoye\org\springdoc\springdoc-openapi-ui\1.7.0\springdoc-openapi-ui-1.7.0.jar;D:\zuoye\org\springdoc\springdoc-openapi-webmvc-core\1.7.0\springdoc-openapi-webmvc-core-1.7.0.jar;D:\zuoye\org\springdoc\springdoc-openapi-common\1.7.0\springdoc-openapi-common-1.7.0.jar;D:\zuoye\io\swagger\core\v3\swagger-core\2.2.9\swagger-core-2.2.9.jar;D:\zuoye\jakarta\xml\bind\jakarta.xml.bind-api\2.3.2\jakarta.xml.bind-api-2.3.2.jar;D:\zuoye\jakarta\activation\jakarta.activation-api\1.2.1\jakarta.activation-api-1.2.1.jar;D:\zuoye\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.9.8\jackson-dataformat-yaml-2.9.8.jar;D:\zuoye\io\swagger\core\v3\swagger-annotations\2.2.9\swagger-annotations-2.2.9.jar;D:\zuoye\io\swagger\core\v3\swagger-models\2.2.9\swagger-models-2.2.9.jar;D:\zuoye\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\zuoye\org\webjars\swagger-ui\4.18.2\swagger-ui-4.18.2.jar;D:\zuoye\com\alibaba\cola\cola-component-exception\4.0.0\cola-component-exception-4.0.0.jar" com.zebra.charge.demo.StartApplication . ____ _ __ _ _ /\\ / ___&#39;_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | &#39;_ | &#39;_| | &#39;_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) &#39; |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.4.RELEASE) 2025-05-29 21:53:16.418 INFO 25336 --- [ main] com.zebra.charge.demo.StartApplication : Starting StartApplication on wnjy2 with PID 25336 (started by 25120 in C:\biili\新建文件夹) 2025-05-29 21:53:16.420 INFO 25336 --- [ main] com.zebra.charge.demo.StartApplication : No active profile set, falling back to default profiles: default 2025-05-29 21:53:17.387 INFO 25336 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http) 2025-05-29 21:53:17.402 INFO 25336 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat] 2025-05-29 21:53:17.402 INFO 25336 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.17] 2025-05-29 21:53:17.472 INFO 25336 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2025-05-29 21:53:17.472 INFO 25336 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1024 ms Logging initialized using &#39;class org.apache.ibatis.logging.stdout.StdOutImpl&#39; adapter. 2025-05-29 21:53:17.610 INFO 25336 --- [ main] c.a.d.s.b.a.DruidDataSourceAutoConfigure : Init DruidDataSource 2025-05-29 21:53:17.799 INFO 25336 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited Registered plugin: &#39;com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor@6009bea&#39; Property &#39;mapperLocations&#39; was not specified. _ _ |_ _ _|_. ___ _ | _ | | |\/|_)(_| | |_\ |_)||_|_\ / | 3.4.0 2025-05-29 21:53:18.726 INFO 25336 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService &#39;applicationTaskExecutor&#39; 2025-05-29 21:53:19.013 INFO 25336 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path &#39;&#39; 2025-05-29 21:53:19.015 INFO 25336 --- [ main] com.zebra.charge.demo.StartApplication : Started StartApplication in 2.879 seconds (JVM running for 3.674) 有错误吗
05-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值