多线程——线程池解析

问题:什么是线程池?线程池的工作原理及使用线程池的好处?

一个线程池管理了一组工作线程,同时还包括了一个任务队列(阻塞队列),用于放置等待执行的任务队列。默认情况下,在创建了线程池以后,线程池中的线程数为0。

当有任务提交,线程池的处理策略如下:

(1)如果此时的线程数小于核心线程数,即使线程池中的线程都处于空闲状态,也要创建新的线程来执行任务。(即每来一个任务,创建一个新线程)

(2)如果此时线程数大于核心线程数,并且未超过最大线程数。判断阻塞队列,阻塞队列未满的话,就将任务放入阻塞队列,等待有线程空闲了再取出执行。

(3)如果此时线程数大于核心线程数,并且未超过最大线程数。并且阻塞队列已满,这时判断线程数是否达到最大线程数。如果未达到最大线程数,则可以通过创建新的线程来完成该任务。

(4)若此时阻塞队列已满,而且线程数已达到最大线程数,那么就要通过RejectedExecutionHandler所指定的拒绝策略拒绝该任务。

*注:处于核心线程数和最大线程数之间的线程会被自动释放,当这写线程中某一线程的空闲时间超过keepAliveTime时,该线程就会被终止。该机制体现了线程池可以动态地调整线程池中的线程数量。

使用线程池的好处:

(1)通过重复利用已经创建好的线程,减少创建线程和线程销毁所花费的时间和系统资源开销。

(2)提高响应速度,当任务到达时,不需要创建新线程而立即执行。

(3)提高线程的可管理性,使用线程池可以对线程进行统一地分配和监控。

(4)如果不使用线程池,有可能造成系统创建大量线程,从而导致系统内存消耗完。

类和接口:

Executor接口、Executors类、ExecutorService接口、AbstractExecutorService抽象类、ThreadPoolExecutor类

线程池继承关系图:

Executor是一个顶层接口,只声明了一个方法,用来执行传进去的任务。

然后ExecutorService继承了Executor接口,并声明了一些方法。

抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService接口中声明的所有方法。

然后ThreadPoolExecutor继承了AbstractExecutorService抽象类。

ThreadPoolExecutor源码解析:

(一)继承实现:

继承自AbstractExecutorService抽象类。

(二)基本属性及默认参数(7个)

(1)corePoolSize:核心线程数,当线程池中的线程数目达到核心线程数时,被提交的任务机会被存放到阻塞队列中

(2)maximumPoolSize:最大线程数,表示线程池中最多能够创建的线程数目。

(3)AliveTime:存活时间,作用于线程数处于核心线程数与最大线程数之间时,当核心线程数与最大线程数之间的某个线程的空闲时间超过该参数,该线程就会被终止。

(4)TimeUnit:AliveTime参数的时间单位。

(5)workQueue:一个阻塞队列,用于存放等待执行的任务。

(6)threadFactory:线程工厂,主要用于线程的创建。

(7)handler:拒绝策略,用于当最大线程数和阻塞队列都满的情况下提交任务的处理,默认取值为抛出异常。

(三)构造方法(4个)

核心构造方法:

    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;
    }

(四)重要方法

(1)execute()

(2)submit()

(3)shutdown()

(4)shutdownNow()

问题:

(1)execute()和submit()的区别:

submit()有返回值,execute()没有返回值。应用时根据提交任务是否有返回值来选择对应方法。

submit()更加方便异常处理,如果任务可能会抛出异常,并且希望外面的调用者可以感知这些异常,就需要使用submit()方法,再通过Future.get抛出的异常。

(2)shutdown()和shutdownNow()的区别:

猜你喜欢

转载自blog.csdn.net/weixin_42479293/article/details/90291637