线程池-lhg

线程池

为了更好地实现用户级的线程调度,更有效地帮助开发人员进行多线程开发,Java 提供了一套 Executor 框架。这个框架中包括了 ScheduledThreadPoolExecutor 和 ThreadPoolExecutor 两个核心线程池。前者是用来定时执行任务,后者是用来执行被提交的任务

在这里插入图片描述

为什么要用线程池

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。

2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

Executors 线程池工具类

Executors 可以类比于 Arrays 和 Collections,Executors 类中包含了一些静态方法,它们负责生成各种类型的线程池 型ExecutorService 实例。

类型特性
newFixedThreadPool固定大小的线程池,当有新的任务提交,线程池如果有空闲线程则立即执行,否则新任务会进入等待队列
newSingleThreadExecutor只用一个线程来执行任务,可以保证任务有序执行
newCachedThreadPool线程池大小不固定,可灵活回收线程,若无可回收,则创建新先线程
newScheduledThreadPool定时线程池,支持定时及周期性任务执行

线程池原理

Executors 利用工厂模式实现的四种线程池,进入四种工厂类后,我们可以发现除了 newScheduledThreadPool 类,其它类均使用了 ThreadPoolExecutor 类进行实现,如下是其构造方法:

public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
                          int maximumPoolSize,//线程池的最大线程数
                          long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                          TimeUnit unit,//时间单位
                          BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
                          ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
                          RejectedExecutionHandler handler) //拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务

RejectedExecutionHandler 拒绝策略,当线程池中的工作线程达到了最大数量, 并且阻塞队列也已经满了,那么拒绝策略会决定如何处理新的任务。 ThreadPoolExecutor 提供了四种策略:

  1. AbortPolicy(是线程池的默认拒绝策略):

    如果使用此拒绝策略,那么将对新的任务抛出RejectedExecutionException异常,来拒绝任务。

  2. DiscardPolicy:

    如果使用此策略,那么会拒绝执行新的任务,但不会抛出异常。

  3. DiscardOldestPolicy:

    如果使用此策略,那么不会拒绝新的任务, 但会抛弃阻塞队列中等待最久的那个线程。

  4. CallerRunsPolicy:

    如果使用此策略,不会拒绝新的任务,但会让调用者执行线程(比如Main线程)。 也就是说哪个线程发出的任务,哪个线程执行。

线程池原理总结:

  • 在创建了线程池后,等来提交过来的任务请求
  • 当调用 execute() 方法添加一个请求任务时,线程池会做如下判断:
    • 如果正在运行的线程池数量小于 corePoolSize,那么马上创建新线程执行任务
    • 如果正在运行的线程池数量大于或等于 corePoolSize,那么将这个任务放入等待队列
    • 如果这个时候等待队列满了且正在运行的线程数量小于 maximumPoolSize ,那么会创建非核心线程来执行任务
    • 如果这个时候等待队列满了且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会启动饱和拒绝策略来执行
  • 当一个线程执行完成任务时,会从队列中取下一个任务来执行
  • 当一个线程无事可做超过一定时间(keepAliveTime)时,线程池会判断:如果当前运行的线程数量大于 corePoolSize,那么这个线程会被停掉

所以线程池的所有任务完成后它最终会收缩到 corePoolSize 的大小

为什么不用 Java 自带的线程池?

Executors 返回的线程池对象的弊端如下:

1、newFixedThreadPool 和 newSingleThreadExecutor

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

LinkedBlockingQueue 队列的默认长度为 Integer.MAX_VALUE(21亿) ,可能会堆积大量请求,从而导致 OOM

2、newCachedThreadPool 和 newScheduledThreadPool

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
}

可以看到允许创建的线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM

手写一个线程池?

public class ThreadPoolExecetorDemo {
    public static void main(String[] args) {
        ExecutorService executorService = new ThreadPoolExecutor(3,
                5,
                2,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());
        //有10个人来柜台办理业务...
        for (int i = 1; i <= 10; i++) {
            executorService.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "\t处理。。");
                try {
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }
}

JUC笔记

JVM笔记

https://github.com/Seazean/JavaNote

JAVA相关的深度技术博客链接

前端笔记

在这里插入图片描述

在这里插入图片描述

https://github.com/xiaolincoder/CS-Base/blob/main/network/4_ip/ip_base.md

https://blog.csdn.net/xjjj064/article/details/120214975

https://blog.csdn.net/cd546566850/article/details/105353791

https://blog.csdn.net/TZ845195485/article/details/93238857

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值