线程池详解

目录

线程池的基本定义:

线程池状态:

线程池的构造方法及七大参数:

线程的拒绝策略:

线程池运行步骤:

线程池的具体介绍

1.newFixedThreadPool

特点:

实例代码:

结果: 

2.newCachedThreadPool

特点:

实例代码:

结果: 

3.newSingleThreadPool

特点:

实例代码:

结果: 

 4.newScheduledThreadPool

特点:

实例代码:

结果: 

  5.newWorkStealingPool

特点:


线程池的基本定义:

线程池特点:线程复用,控制最大并发数,管理线程

  1. 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗
  2. 提高相应速度,当任务到达时,任务可以不需要等到线程创建,就能立即执行。
  3. 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,,使用线程池可以进行统一的分配,调优和监控

线程池状态:

状态名

说明

RUNNING

SHUTDOWN

不会接收新任务,但会处理阻塞队列剩余 任务

STOP

会中断正在执行的任务,并抛弃阻塞队列 任务

TIDYING

任务全执行完毕,活动线程为 0 即将进入 终结

TERMINATED

终结状态

线程池的构造方法及七大参数:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

 参数详解:

  • corePoolSize 核心线程数目 (最多保留的线程数)
  • maximumPoolSize 最大线程数目(核心线程+救急线程总共的数目)
  • keepAliveTime 生存时间 -(针对救急线程 )
  • unit 时间单位 (针对救急线程) 
  • workQueue 阻塞队列
  • threadFactory 线程工厂 - 可以为线程创建时起个好名字
  • handler 拒绝策略--4种

线程的拒绝策略:

AbortPolicy

让调用者抛出 RejectedExecutionException 异常。(默认策略)
CallerRunsPolicy让调用者运行任务。(在主线程中调用ThreadPool.submit ,采用此策略会让主线程来自行运行内容)
DiscardPolicy放弃本次任务,不处理也不抛异常。
DiscardOldestPolicy放弃队列中最早的任务,然后把当前任务加入队列中尝试再次提交当前任务。简称:本任务取而代之。

线程池运行步骤:

  1. 创建线程池,等待提交过来的任务请求
  2. 调用execute()方法添加一个请求任务时,会有一下情况
    1. 如果正在运行的线程数量 < corePoolSize,那么马上创建线程运行这个任务。(所以线程是懒惰创建的,只有提交了任务才会创建线程
    2. 如果正在运行的线程数量 >= corePoolSize,将这个任务放入队列中。(要求队列必须是有界的
    3. 如果这个时候队列满了,且正在运行的线程数量 < maximumPoolSize,那么开始创建急救线程来执行这个任务。(救急线程处理新来的任务,而不是队列中已等待的数据
    4. 如果这个时候队列满了,且正在运行的线程数量 >= maximumPoolSize,那么线程池执行设定好的拒绝策略来执行。
  3. 当线程完成任务时,会从队列中取下一个任务来执行。
  4. 当一个线程休息的时间超过一定的时间(keepAliveTime ),线程池会判断如果当前的时间 >= corePoolSize ,那么这个线程就会被停掉。

线程池的具体介绍

1.newFixedThreadPool

创建一个固定大小的线程池。

适合任务量已知,相对耗时的任务

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

特点:

  1. keepAliveTime为0
  2. corePoolSize = maximumPoolSize ,
  3. 阻塞队列是:LinkedBlockingQueue。是无界的,可以放任意数量的任务。

实例代码:

  ExecutorService threadPool = Executors.newFixedThreadPool(5)
        for (int i = 0; i < 10; i++) {
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"\t 处理业务");
            });
        }

结果: 

 

2.newCachedThreadPool

可缓存线程的线程池。若线程数超过任务所需,那么多余的线程会被缓存一段时间后才被回收,若线程数不够,则会新建线程。

适合任务数比较密集,但每个任务执行时间较短的情况。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

特点:

  1. 核心线程数是 0, 最大线程数是 Integer.MAX_VALUE
  2. 救急线程的空闲生存时间是 60s,意味着全部都是救急线程(60s 后可以回收)。
  3. 队列采用了 SynchronousQueue 实现特点是,它没有容量,没有线程来取是放不进去的
  4. 如果没有空闲线程,那么就创建一个新的线程,反之使用旧的线程执行任务。

实例代码:

   private static void ThreadPoolInit() {
        ExecutorService threadPool = Executors.newCachedThreadPool();  //一池n个处理线程
        for (int i = 0; i < 15; i++) {
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"\t 处理业务");
            });
        }
    }

 private static void ThreadPoolInit() {
        ExecutorService threadPool = Executors.newCachedThreadPool();  //一池n个处理线程
        for (int i = 0; i < 15; i++) {
            threadPool.execute(()->{
                Thread.sleep(5);
                System.out.println(Thread.currentThread().getName()+"\t 处理业务");
            });
        }
    }

结果: 

 

3.newSingleThreadPool

适合:多个任务排队执行

 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

特点:

  1. 创建一个单一的线程池,他只会用唯一的工作线程来执行任务。
  2. corePoolSize = maximumPoolSize = 1,
  3. 生存时间为0s
  4. 阻塞队列是:LinkedBlockingQueue
  5. 阻塞队列是无界的,可以放任意数量的任务。

实例代码:

  ExecutorService threadPool1 = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+"\t 处理业务");
            });
        }

结果: 

 

 4.newScheduledThreadPool

适合:周期性执行任务的场景,需要限制线程数量的场景。

  public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

特点:

  1. 最大线程数为Integer.MAX_VALUE
  2. 阻塞队列是DelayedWorkQueue
  3. 生存时间为0s
  4. scheduleAtFixedRate() :按某种速率周期执行
  5. scheduleWithFixedDelay():在某个延迟后执行

实例代码:

线程初次执行的延迟时间为1s,后每3s进行一次线程执行。

 private static void ThreadPoolInit() {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        System.out.println("start-- Time" + System.currentTimeMillis());
        scheduledExecutorService.scheduleWithFixedDelay(()->{
            System.out.println("current Time" + System.currentTimeMillis());
            System.out.println(Thread.currentThread().getName()+"正在执行");
        }, 1, 3, TimeUnit.SECONDS);


    }

结果: 

 

  5.newWorkStealingPool

具有抢占式操作的线程池,每个线程都有一个任务队列存放任务。底层用的ForkJoinPool 来实现的,任务按照工作线程均分,先工作完的线程去帮助没处理完的线程工作。达到最快完成工作的现象。适合使用在很耗时的任务中。

  public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

特点:

  1. 可以传入线程的数量,不传入,则默认使用当前计算机中可用的cpu数量

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值