线程池使用过吗?谈谈对于ThreadPoolExecutor的理解

使用线程池的好处

1、线程复用;
2、控制最大线程数;
3、管理线程

JDK提供几种线程池的使用方法 (面试问到用哪种,下面的都不用,开发中手写线程池)

java中的线程池是通过Executor框架实现
线程池使用过吗?谈谈对于ThreadPoolExecutor的理解_第1张图片

一、newSingleThreadPool 创建单线程化的线程池

/**
 * 创建单线池化的的线程池newSingleThreadExecutor
 */
	ExecutorService executor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 3; i++) {
     
        executor.execute(() -> {
     
            System.out.println(Thread.currentThread().getName() + "获取池连接");
            System.out.println(Thread.currentThread().getName() + "释放池连接");
        });
    }

查看下newSingleThreadExecutor底层源码

线程池使用过吗?谈谈对于ThreadPoolExecutor的理解_第2张图片

本质上还是去创建一个ThreadPoolExecutor 只是把corePoolSize 和maximunPoolSize 都设置为1
采用的是LinkedBlockingQueue 阻塞队列

线程池使用过吗?谈谈对于ThreadPoolExecutor的理解_第3张图片

二、newFixedThreadPool ( int )

/**
 * 创建定长的线程池newFixedThreadPool
 */
    ExecutorService executor = Executors.newFixedThreadPool(5);//创建拥有五个线程的线程池
    for (int i = 0; i < 50; i++) {
     
        executor.execute(() -> {
     
            System.out.println(Thread.currentThread().getName() + "获取池连接");
            System.out.println(Thread.currentThread().getName() + "释放池连接");
        });
    }

查看下newFixedThreadPool底层源码
线程池使用过吗?谈谈对于ThreadPoolExecutor的理解_第4张图片

这里corePoolSize 和maximunPoolSize 相等于传进来的参数

上面两种采用的都是阻塞队列LinkedBlockingQueue

public LinkedBlockingQueue() {
     
        this(Integer.MAX_VALUE);//这里这么大 控制不好容易OOM
    }

三、可缓存的线程池,空闲则回收,忙则新建线程

/**
 * 3、可缓存的线程池,空闲则回收,忙则新建线程 newCachedThreadPool
 * 动态的增加缩减线程数量
 */
    ExecutorService executor = Executors.newCachedThreadPool();
    for (int i = 0; i < 1000; i++) {
     
        executor.execute(() -> {
     
            System.out.println(Thread.currentThread().getName() + "获取池连接");
            System.out.println(Thread.currentThread().getName() + "释放池连接");
        });
    }

查看下他的底层实现
线程池使用过吗?谈谈对于ThreadPoolExecutor的理解_第5张图片
底层采用的是SynchronousQueue
当线程空闲60s就回收

ThreadPoolExecutor的七大参数介绍

1、corePoolSize :线程池中的常驻核心线程数

2、maximumPoolSize :线程池能够容纳同时执行的最大线程数,此数值必须大于等于1

3、keepAliveTime :多余的空闲线程的存活时间。当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,多余空闲线 程会被销毁直到只剩下corePoolSize个线程为止

4、unit: keepAliveTime的单位

5、workQueue :任务队列,被提交但尚未被执行的任务

6、.threadFactory:表示,生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可

7、handler:拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数时,如何来拒绝

说说线程池的底层工作原理

1、创建线程池后,等待提交过来的任务请求
2、当调用execute()方法添加一个请求任务时,线程会作如下判断:

		1、如果正在运行的线程数量小于corePoolSize,那么马上分配线程运行这个任务;
		2、如果正在运行的线程数量大于或等于corePoolSize,那么这个任务将进入等待队列;
		3、如果这时队列满了且正在运行的线程数量还是小于maximumPoolSize,那么还是要创建非核心线程立即运行这个任务
		4、 如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行

3、当一个线程完成任务时,他会从队列中取下一个任务来执行
4、一个线程无事可做超过一定的时间keepAliveTime时,线程池会判断:

			如果当前运行的线程数量超过corePoolSize,那么这个线程就会被停掉
			所以线程池的所有任务完成后最终会收缩到corePoolSize的大小

注意点:从corePoolSize扩充到maximumPoolSize,创建的非核心线程是分配给当前到达的任务,而不是队列中
当非核心线程达到空闲时间,则会被线程池回收

你可能感兴趣的:(面试题集合)