线程池

 

 

 原理根据上图流程说出来就好了

原理:

1.提交任务

2.先判断核心线程池是否都满了,没有满就创建线程执行任务

3.如否则看队列里面线程是否已经满了,没有满的话就任务储存在队列里面。

4.如果队列满了,看线程池是否满了,如果没有满,创建线程执行任务;

5.如果非核心线程池满了,执行拒绝策略。

 

 线程池都有哪几种工作队列:
    1、有界任务队列,ArrayBlockingQueue
    是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
    2、无界任务队列,LinkedBlockingQueue
    一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列
    3、直接提交队列,SynchronousQueue
    一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法        Executors.newCachedThreadPool使用了这个队列。
    4、优先级任务队列,PriorityBlockingQueue
    一个具有优先级的无限阻塞队列。
 
 
 用户线程和守护线程有什么区别?
    守护线程是依赖于用户线程,用户线程退出了,守护线程也就会退出,典型的守护线程如垃圾回收线程。
    用户线程是独立存在的,不会因为其他用户线程退出而退出。
    默认情况下启动的线程是用户线程,通过setDaemon(true)将线程设置成守护线程,这个函数务必在线程启动前进行调用,否则会报java.lang.IllegalThreadStateException异常,启动的线程无法变成守护线程,而是用户线程。
 
 
  四个策略:
                  ThreadPoolExecutor.AbortPolicy() //缺省策略,抛出java.util.concurrent.RejectedExecutionException异常                
                  ThreadPoolExecutor.CallerRunsPolicy(),重试添加当前的任务,他会自动重复调用execute()方法               
                  ThreadPoolExecutor.DiscardOldestPolicy(),抛弃旧的任务    
                  ThreadPoolExecutor.DiscardPolicy(),抛弃当前的任务
 
 
如果设置线程池的大小?
  CPU密集型任务应配置尽可能小的线程,如配置CPU个数+1的线程数,IO密集型任务应配置尽可能多的线程,因为IO操作占用CPU,不要让CPU闲下来,应加大线程数量,如配置两倍           CPU个数+1,而对于混合型的任务,如果可以拆分,拆分成IO密集型和CPU密集型分别处理,前提是两者运行的时间是差不多的,如果处理时间相差很大,则没必要拆分了。
 
         CPU密集型: cpu使用率较高(也就是一些复杂运算,逻辑处理),所以线程数一般只需要cpu核数的线程就可以了。

   IO密集型:cpu使用率较低,程序中会存在大量I/O操作占据时间,导致线程空余时间出来,所以通常就需要开cpu核数的两倍的线程, 当线程进行I/O操作cpu空暇时启用其他线程继续使用                             cpu,提高cpu使用率 通过上述可以总结出:线程的最佳数量: 最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目 线程等待时间所占比例越高,需                             要越多线程。线程CPU时间所占比例越高,需要越少线程。这一类型在开发中主要出现在一些读写操作频繁的业务逻辑中

 

   高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换

        并发不高、任务执行时间长的业务这就需要区分开看了:

    a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务

    b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换

 
线程池有哪些参数?

1. corePoolSize 核心线程数目 - 池中会保留的最多线程数。

2. maximumPoolSize 最大线程数目 - 核心线程+救急线程的最大数目。

3. keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放。

4. unit 时间单位 - 救急线程的生存时间单位,如秒、毫秒等。

5. workQueue - 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务。

6. threadFactory 线程工厂 - 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等。

拒绝策略
 
 
 
线程安全就是?
在多线程环境中,能永远保证程序的正确性,只有存在共享数据时才需要考虑线程安全问题。
 
说说几种常见的线程池及使用场景
newSingleThreadExecutor创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,如果这个线程异常结束,会有另一个取代它,保证顺序执行(我觉得这点是它的特色)。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的 。
 
newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。 
 
newCachedThreadPool创建一个可缓存的线程池。这种类型的线程池特点是: 
    1).工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。 
    2).如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。 
 
newScheduleThreadPool创建一个定长的线程池,而且支持定时的以及周期性的任务执行,类似于Timer。(这种线程池原理暂还没完全了解透彻) 
 

 

核心线程数为什么一直能存活,非核心线程数为什么不能一直存活?

也就是corePoolSize和keepAliveTime,上述代码块也包含了这两个参数的源码注释和中文翻译。keepAliveTime参数指定了非核心线程的存活时间,非核心线程的空闲时间一旦达到这个值,就会被销毁,而核心线程则会继续存活,只要有线程存活,线程池也就不会自动关闭。

 

 

线程池的状态总共有 5 种:RUNNING:运行状态、SHUTDOWN:关闭状态、STOP:停止状态、TIDYING:整理状态和 TERMINATED:销毁状态

 

posted @   雪域飞魂  阅读(218)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示