欢迎来到皮皮网网站!

【tsim后端源码】【新闻网校源码】【批量修改源码信息】jdk5线程池源码_jdk 线程池

时间:2024-12-29 20:12:33 来源:adminQp源码

1.ExecutorService和TaskExecutor的区别和使用
2.线程池调优之动态参数配置
3.Java高并发编程实战5,线k线异步注解@Async自定义线程池

jdk5线程池源码_jdk 线程池

ExecutorService和TaskExecutor的区别和使用

       ExecutorService 和 TaskExecutor 都是使用线程池来管理多线程异步执行任务,他们有什么关联和区别,什么时候该用哪个呢?

        ExecutorService 属于 java.util.concurrent 包下面的,继承于 java.util.concurrent.Executor ,一般使用 java.util.concurrent.Executors 工厂类创建。 Executor 和 ExecutorService 都是 JDK 5 才提供的。

        TaskExecutor 属于 org.springframework.core.task 包下面,也是继承与 java.util.concurrent.Executor

        Java 1.7 引入了一种新的并发框架,程池程池主要用于实现“分而治之”的算法,特别是分治之后递归调用的函数,例如 quick sort 等。

        ForkJoinPool 最适合的是计算密集型的任务,如果存在 I/O,线程间同步,sleep() 等会造成线程长时间阻塞的情况时,最好配合使用 ManagedBlocker。

        具体请移步至

        用于延时或者定期执行的异步任务/线程

        提供线程池执行任务

        ThreadPoolTaskExecutor 同样是提供线程池执行任务,但是可以使用xml或者JavaBean的形式进行配置,初始化。同样, ThreadPoolTaskExecutor 是使用 ThreadPoolExecutor 。即也是 ThreadPoolExecutor 的Spring包装。

       ThreadPoolTaskScheduler 是 ScheduledThreadPoolExecutor 一个spring形式的包装。Spring中任务的调度使用的就是这个类,比如 @Scheduled

       spring的 TaskExecutor 的两个常用实现类均是基于 Executor 实现类的包装,使其更加方便使用,更好的融入spring bean生态。

        关于线程池的创建,拒绝策略,任务的执行状态,任务取消,等待任务完成等,网上资料很多了,将来有机会整理一下。

线程池调优之动态参数配置

       前言线程池的核心参数配置在网上有一大堆的文章介绍,这次结合个人理解写一篇文章记录一下,源码以便加深印象和后续查阅。线k线线程池配置参数

       corePoolSize:线程池核心线程数

       maximumPoolSize:线程池最大线程数

       keepAliveTime:允许线程空闲时间(对非核心工作线程的程池程池回收)

       TimeUnit:线程空闲时间单位

       workQueue:线程队列(当核心线程数满了,新的源码tsim后端源码任务就会放入这个队列中)

       threadFactory:线程工厂(用于创建工作线程,自定义线程工厂可以指定线程名称)

       handler:线程池拒绝策略(当线程队列满了且最大线程数也满了,线k线就会执行任务拒绝策略,程池程池默认有4种)

       allowCoreThreadTimeOut:控制核心工作线程是源码否需要被回收

常规线程池参数配置

       -首先提问一个面试题:现有个任务,台服务器,线k线每台机器都是程池程池4核,在任务不丢弃情况下,源码新闻网校源码线程池参数该怎么配置最合理呢?

       -把这个问题拆分一下,线k线个任务,程池程池台机器,源码那么每台机器就负责个任务(常规轮训负载均衡模式,不考虑其他额外情况),每台机器都是4核,那么就可以设置核心线程数和最大线程数为4,线程队列大小为即可。

       -当然也可以把核心和最大线程数设置为5(n+1)个,线程队列大小为,这样是批量修改源码信息为了防止线程偶尔由于页缺失故障或者其他原因暂停,出多来的一个线程也能确保CPU的调度时钟周期不会被浪费,相当于备用线程。

       如果任务是CPU密集型配置:工作线程=cpu核心数+1;

       如果任务是IO密集型场景:工作线程=cpu核心数*2;

       所以上面例子中就是基于CPU密集型任务配置线程池。而且网上大部分文章描述线程池配置也是基于这两点来分析的。

       可惜理想很丰满,现实很骨感。在实际工作场景中,其实没那么容易区分线程中执行的任务是CPU密集还是IO密集,而且服务器上还会有其他应用线程抢占CPU资源,就算还有一些其他的公式计算配置线程池参数,那也是营销软件展示源码基于理想场景情况下进行配置的,所以上述配置更多的还是应用于面试中。

动态配置线程池参数

       上述中既然不能一次定义适配所有场景的线程池参数,那么如果可以根据不同业务场景动态配置线程池参数,通过人工干预介入来适配大部分场景也行的

       正好在JDK的自定义线程池ThreadPoolExecutor里,提供了动态扩展线程池核心参数的方法

       可以在运行期间的线程池使用此方法可以覆盖原来配置的值:

ThreadPoolExecutor线程池提供了5种配置参数可供动态更新:核心线程池,最大线程数,线程工厂,线程空闲时间,拒绝策略。

       这里主要讨论的是核心线程池和最大线程池两种参数配置:

/****@Author:ZRH*@Date://:*/@Slf4jpublicclassExecutorTest{ publicstaticvoidmain(String[]args)throwsException{ finalThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(2,3,,TimeUnit.SECONDS,newLinkedBlockingQueue<>(7),newThreadPoolExecutor.DiscardPolicy());for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}logExecutorInfo(threadPoolExecutor);threadPoolExecutor.setCorePoolSize(5);threadPoolExecutor.setMaximumPoolSize(5);logExecutorInfo(threadPoolExecutor);Thread.currentThread().join();}privatestaticvoidlogExecutorInfo(ThreadPoolExecutorexecutor){ log.info("线程池核心线程数="+executor.getCorePoolSize()+",线程池最大线程数="+executor.getMaximumPoolSize()+",返佣app源码线程池队列剩余任务="+executor.getQueue().size()+",线程池活跃线程数="+executor.getActiveCount()+",线程池任务完成数"+executor.getCompletedTaskCount());}}

       看执行结果:刚开始线程池里核心线程数2个、最大线程数3个、剩下7放队列。活跃的线程也只有3个。

       然后更改核心线程和最大线程数为5后,线程池里对应的核心线程数和最大线程数也增加至5个,活跃的工作线程也是5个。说明更改配置成功。

       注:更新线程池参数时,核心线程数不能超过最大线程数配置。否则配置最后不会生效。

publicstaticvoidmain(String[]args)throwsException{ finalThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(2,3,,TimeUnit.SECONDS,newLinkedBlockingQueue<>(7),newThreadPoolExecutor.DiscardPolicy());for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}logExecutorInfo(threadPoolExecutor);threadPoolExecutor.setCorePoolSize(5);//threadPoolExecutor.setMaximumPoolSize(5);logExecutorInfo(threadPoolExecutor);Thread.currentThread().join();}

       上图中把核心线程数更新为5,最大线程数不改动任为3。最后看执行结果,最终的活跃线程还是3个,说明配置没有生效,具体源码在ThreadPoolExecutor类的getTask()方法里,感兴趣的同学可以去看一下...

动态更新线程队列

       ThreadPoolExecutor线程池并没有动态配置线程池队列大小的方法

       想自己操作一下也是很简单的,只需要自定义实现一个队列,可以直接把LinkedBlockingQueue复制一份,并把capacity参数设定为可更改

publicstaticvoidmain(String[]args)throwsException{ finalThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(2,3,,TimeUnit.SECONDS,newCustomLinkedBlockingQueue<>(7),newThreadPoolExecutor.DiscardPolicy());for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}logExecutorInfo(threadPoolExecutor);threadPoolExecutor.setCorePoolSize(5);threadPoolExecutor.setMaximumPoolSize(5);CustomLinkedBlockingQueuequeue=(CustomLinkedBlockingQueue)threadPoolExecutor.getQueue();queue.setCapacity();for(inti=0;i<;i++){ threadPoolExecutor.execute(()->{ try{ logExecutorInfo(threadPoolExecutor);Thread.sleep();}catch(InterruptedExceptione){ }});}Thread.currentThread().join();}

       看结果,后续添加的任务会放入队列中,并且队列大小也超过第一次设置大小,说明配置成功

最后

       参考:Java线程池实现原理及其在美团业务中的实践

       虚心学习,共同进步-_-

Java高并发编程实战5,异步注解@Async自定义线程池

       @Async注解的作用是异步处理任务。

       在使用@Async时,如果不指定线程池的名称,默认线程池是Spring默认的线程池SimpleAsyncTaskExecutor。

       默认线程池的配置如下:

       从最大线程数可以看出,在并发情况下,会无限制地创建线程。

       也可以通过yml重新配置:

       也可以自定义线程池,下面通过简单的代码来实现@Async自定义线程池。

       二、代码实例

       导入POM

       配置类AsyncTaskConfig

       UserController

       UserService

       UserServiceImpl

       三、为什么在文件内执行异步任务,还是一个线程,没有实现@Async效果?

       在众多尝试中,找到了@Async失效的几个原因:

       四、配置中使用了ThreadPoolTaskExecutor和ThreadPoolExecutor,这两个有什么区别?

       ThreadPoolTaskExecutor是spring core包中的,而ThreadPoolExecutor是JDK中的JUC。

       1、initialize()

       查看ThreadPoolTaskExecutor的initialize()方法

       2、initializeExecutor抽象方法

       再查看initializeExecutor抽象方法的具体实现类,其中有一个就是ThreadPoolTaskExecutor类,查看它的initializeExecutor方法,使用的就是ThreadPoolExecutor。

       因此可以了解到ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装。

       五、核心线程数

       配置文件中的线程池核心线程数为何配置为Runtime.getRuntime().availableProcessors()?

       获取的是CPU核心线程数,也就是计算资源。

       在实际中,需要对具体的线程池大小进行调整,可以通过压测及机器设备现状,进行调整大小。如果线程池太大,则会造成CPU不断的切换,对整个系统性能也不会有太大的提升,反而会导致系统缓慢。

       六、线程池执行流程

更多相关资讯请点击【百科】频道>>>