一、什么是线程池

二、使用线程池的好处

三、涉及到的类和接口

常用的线程池接口和类都在 java.util.concurrent包下,大致为:

多线程【线程池】-LMLPHP

ExecutorService接口的实现类最常用的为以下两个:

和 Array -> Arrays、Collection -> Collections 一样,线程池的创建也是有工具类可以使用的:

四、线程池种类

在 JDK 8 以后,一共有 5 种线程池,分别为:

这些线程池都能由 Executors 工具类来进行创建,分别对应以下方法:

对于 newWorkStealingPool 的补充:

五、如何使用线程池

(一)使用步骤
(二)案例代码

需求:使用线程池管理线程来简单的模拟买票程序。

public class Demo(){
    public static void main(String[] args) {
        test();
    }

    public static void test(){
        //1、创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(4);

        //2、创建任务
        Runnable runnable = new Runnable(){
            private int tickets = 100;

            @Override
            public void run() {
                while (true){
                    if(tickets <= 0){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName()+"卖了第"+tickets+"张票");
                    tickets--;
                }
            }
        };

        //3、将任务提交到线程池(需要几个线程来执行就提交几次)
        for (int i=0; i<5; i++){
            pool.submit(runnable);
		}

        //4、关闭线程池
        pool.shutdown();
}

补充:

execute() 和 submit() 的区别:

六、线程池底层源码查看

newFixedThreadPool

多线程【线程池】-LMLPHP

newCachedThreadPool

多线程【线程池】-LMLPHP

newSingleThreadExecutor

多线程【线程池】-LMLPHP

newScheduledThreadPool

多线程【线程池】-LMLPHP

多线程【线程池】-LMLPHP

七、线程池7大参数

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.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

八、线程池底层工作原理

九、线程池的4大拒绝策略

线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列也已经排满了,再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。

JDK 内置的拒绝策略如下:

以上内置拒绝策略均实现了 RejectedExecutionHandler 接口,若以上策略仍无法满足实际需要,完全可以自己扩展 RejectedExecutionHandler 接口。

十、线程池的实际使用

通过查看 Executors 提供的默认线程池的底层源码后,我们会发现其有如下弊端:

1)FixedThreadPool 和 SingleThreadPool:

2)CachedThreadPool 和 ScheduledThreadPool:

并且在《阿里巴巴Java开发手册》中也有指出,线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式手动创建,这样的处理方式能让程序员更加明确线程池的允许规则,从而规避资源耗尽的风险。

小结:在实际开发中不会使用 Executors 创建,而是手动创建,自己指定参数。

十一、线程池的手动创建

多线程【线程池】-LMLPHP

以上的参数是随手写的,实际开发中参数的设置要根据业务场景以及服务器配置来进行设置。

十二、线程池配置合理线程数

设置线程池的参数时,需要从以下 2 个方面进行考虑:

(一)CPU 密集型
(二)IO 密集型

线程数的设置参考文章:

http://mp.weixin.qq.com/s__biz=MzI5MzYzMDAwNw==&mid=2247488456&idx=4&sn=80ee015180d46f2bd5b26c166b7dab0a&chksm=ec6e6a90db19e3867f8ea9fd5da01c3378431d6dcf940eb9820c4ab917e05851471102515d17&scene=0&xtrack=1#rd

http://mp.weixin.qq.com/s__biz=MzU1MzUyMjYzNg==&mid=2247484319&idx=1&sn=6a22ad5e324562c900a66624239cc6eb&chksm=fbf0c73ccc874e2a5d0a9c9d8e030e426104a52247b11a0069662a3d41a775f8c5332aba3981&mpshare=1&scene=24&srcid=&sharer_sharetime=1591622673427&sharer_shareid=5d06ca706f31f4d058e964b8b7ccfcc9#rd

Java新手,若有错误,欢迎指正!

02-21 01:15