JUC之线程池的学习

一、什么是线程池

线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务。

它的主要特点为:线程复用;控制最大并发数;管理线程
补充任务队列的概念:存放被提交但未被执行的任务的队列。

二、为什么要使用线程池

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

三、线程池如何使用

1.架构说明

Java中的线程池是通过Executor框架实现的,该框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor这几个类
在这里插入图片描述
面试题:说一下executor和executors的区别
1.Executor
Executor提供了execute()接口,来执行已提交的 Runnable 任务的对象。它只包含一个函数接口。
2.Executors
Executors是个静态工厂类。它通过静态工厂方法返回ExecutorServiceScheduled,ExecutorService、ThreadFactory 和 Callable 等类的对象。

2.编码实现

Executors中获取线程池的方法:

Executors.newFixedThreadPool(int):创建一个有固定数量线程的线程池(执行长期任务性能好)

ExecutorService threadPool = Executors.newFixedThreadPool(5);//一池5个工作线程,类似于一个银行有5个受理窗口

Executors.newSingleThreadExecutor():创建只包含一个线程的线程池

ExecutorService threadPool = Executors.newSingleThreadExecutor();//一池1个工作线程,类似于一个银行有1个受理窗口

Executors.newCachedThreadPool():根据需要创建新线程的线程池

ExecutorService threadPool = Executors.newCachedThreadPool();//一池N个工作线程,类似于一个银行有N个受理窗口

为什么不推荐使用
FixedThreadPool 使用无界队列 LinkedBlockingQueue,当线程池中的线程数达到 corePoolSize 后,新任务将在无界队列中等待,因此线程池中的线程数不会超过 corePoolSize,运行中的 FixedThreadPool(未执行 shutdown()或 shutdownNow())不会拒绝任务,在任务比较多的时候会导致 OOM(内存溢出)。
FixedThreadPool 的 corePoolSize 和 maximumPoolSize 都被设置为 nThreads
SingleThreadExecutor同上
CachedThreadPool 的corePoolSize 被设置为空(0),maximumPoolSize被设置为
CachedThreadPool允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。

3.ThreadPoolExecutor底层原理

在这里插入图片描述

四、线程池的重要参数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

7大参数:
1、corePoolSize:核心线程池大小
线程池维护线程的最少数量。线程池至少会保持改数量的线程存在,即使没有任务可以处理。(注意:这里说的至少是指线程达到这个数量后,即使有空闲的线程也不会释放,而不是说线程池创建好之后就会初始化这么多线程)
2、maximumPoolSize:最大线程池大小
线程池最多可创建的线程数,即使队列中的任务满了线程数量也不会超过maximumPoolSize
3、keepAliveTime:线程池中超过corePoolSize数目的空闲线程的最大存活时间
当前池中线程数量超过corePoolSize时,当空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
4、unit: keepAliveTime的单位
5、workQueue:任务队列,存放被提交但尚未被执行的任务
6、threadFactory:用于创建线程的线程工厂
7、handler:拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝请求执行的runnable的策略

五、线程池底层工作原理(待填坑)

线程池用哪个?生产中如何设置合理参数

六、线程池的拒绝策略(粗略)

在这里插入图片描述
在使用线程池并且使用有界队列的时候,如果队列满了,任务添加到线程池的时候就会有问题,针对这些问题java线程池提供了以下几种策略:
在这里插入图片描述
(1)AbortPolicy:直接抛出异常,系统正常工作,线程池的默认策略
(2)DiscardPolicy:丢弃添加失败的任务并且不会抛出任何异常
(3)DiscardOldestPolicy:丢弃最早的任务请求,再次尝试添加当前任务
(4)CallerRunsPolicy:主线程自己调用excute()方法来执行当前添加失败任务

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值