线程池详解

线程池

背景:经常创建和销毁线程,消耗特别大的资源,比如并发的情况下的线程,对性能影响很大。线程池就是问题为了解决这个问题,提前创建好多个线程,放在线程池中,使用时直接获取,使用完放回线程池中,可以避免频繁的创建、销毁,实现重复利用。

线程池就是首先创建一些线程,他们的集合称之为线程池。线程池在系统启动时会创建大量空闲线程,程序将一个任务传递给线程池,线程池就会启动一条线程来执行这个任务,执行结束后线程不会销毁(死亡),而是再次返回到线程池中成为空闲状态,等待执行下一个任务。

优点

  • 提高相应速度(减少创建线程的时间)
  • 降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
  • 便于线程管理:corePoolSize:核心池的大小。maximumPoolSize:最大线程数。
  • keepAliveTime:线程没有任务时最多保持多长时间后终止。

怎么用

1、使用现成的JUC包下的Executors

JUC包下的Executors,打开你的idea随便new个类,轻轻敲出Executors,再加个“.”就能看到它的方法

https://note.youdao.com/yws/public/resource/c3010d52b6ff9b39183303a884503afd/xmlnote/9D8F8B9178144DEB8566D50177EB48FB/35484

 但是阿里巴巴开发规范不推荐用现成的,因为这几种都可能造成内存溢出,所以最好自己创建,这样也能更好的理解线程池原理;

public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            singleThreadExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println("newSingleThreadExecutor当前线程:"+Thread.currentThread().getName());
                }
            });
        }

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            fixedThreadPool.execute(()->{
                System.out.println("newFixedThreadPool线程名称:"+Thread.currentThread().getName());
            });
        }

    }
}
2、通过线程工厂自己创建线程池
  ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                5, //核心线程数,可以同时运行的线程数量
                10, //最大线程数,任务队列装满的时候,当前可以同时运行的线程数变为这个数
                1L,//等待时间,当线程池中的线程数量大于核心线程数,如果没有新的任务过来,核心线程数以外的线程不会立刻被回收,而是等待这个时间到了才进行回收,作用的话我想就是避免线程创建销毁带来的内存消耗吧
                TimeUnit.SECONDS,//等待时间的单位
                new ArrayBlockingQueue<>(100),//任务队列,100是设置队列容量
                new ThreadPoolExecutor.CallerRunsPolicy());//饱和策略,任务队列满了并且当前线程数达到最大线程数会触发这个机制,有四种,先别问,下面会讲
线程池参数
  1. corePoolSize(必填):核心线程数。
  2. maximumPoolSize(必填):最大线程数。
  3. keepAliveTime(必填):线程空闲时长。如果超过该时长,非核心线程就会被回收。
  4. unit(必填):指定keepAliveTime的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
  5. workQueue(必填):任务队列。通过线程池的execute()方法提交的Runnable对象将存储在该队列中。
  6. threadFactory(可选):线程工厂。一般就用默认的。
  7. handler(可选):拒绝策略(饱和策略)。当线程数达到最大线程数时就要执行饱和策略。
拒绝策略可选值
  1. AbortPolicy(默认):放弃任务并抛出RejectedExecutionException异常。
  2. CallerRunsPolicy:由调用线程处理该任务。
  3. DiscardPolicy:放弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
  4. DiscardOldestPolicy:放弃队列最早的未处理任务,然后重新尝试执行任务。
四种饱和策略

任务队列
  1. 如果当前运行的线程小于corePoolSize,则新任务会直接运行,不会存入队列
  2. 如果当前运行的线程大于等于 corePoolSize,则 Executor始终首选将请求加入队列,而不添加新的线程。
  3. 如果无法将任务加入队列,则创建新的线程,除非创建此线程后线程数会超出 maximumPoolSize,在这种情况下,会触发饱和策略。

线程池执行流程

https://note.youdao.com/yws/public/resource/c3010d52b6ff9b39183303a884503afd/xmlnote/1CE37FFE08774300BC5BBE83526C61B9/39404

线程池的工作机制

在线程池的编程模式下,任务是分配给整个线程池的,而不是直接提交给某个线程,线程池拿到任务后,就会在内部寻找是否有空闲的线程,如果有,则将任务交个某个空闲线程。

 使用线程池的原因

多线程运行时,系统不断创建和销毁新的线程,成本非常高,会过度的消耗系统资源,从而可能导致系统资源崩溃,使用线程池就是最好的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值