1、初始化线程的 4 种方式

1)、继承 Thread
2)、实现 Runnable 接口
3)、实现 Callable 接口 + FutureTask (可以拿到返回结果,可以处理异常)
4)、线程池
方式 1 和方式 2:主进程无法获取线程的运算结果。不适合当前场景
方式 3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致 服务器资源耗尽。
方式 4:通过如下两种方式初始化线程池

Executors.newFiexedThreadPool(3); 
//或者 new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit unit, workQueue, threadFactory, handler);

通过线程池性能稳定,也可以获取执行结果,并捕获异常。但是,在业务复杂情况下,一 个异步调用可能会依赖于另一个异步调用的执行结果。

全部测试代码:

public static ExecutorService service = Executors.newFixedThreadPool(10);

public static void main(String[] args) throws ExecutionException, InterruptedException {
// Runable01 runable01 = new Runable01();
// new Thread(runable01).start();

// FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
// new Thread(futureTask).start();
// System.out.println(futureTask.get() + "");

//使用线程池
Future<?> future = service.submit(new Callable01());
System.out.println(future.get());

/**
* int corePoolSize, 核心线程数,空闲也不消失
* int maximumPoolSize, 最大线程数
* long keepAliveTime, (maximumPoolSize-corePoolSize)的存活时间
* TimeUnit unit, 时间队列
* BlockingQueue<Runnable> workQueue, 阻塞队列,存活任务,有空闲时到此队列取任务运行
* ThreadFactory threadFactory, 线程工厂
* RejectedExecutionHandler handler 队列满了,按照拒绝策略拒绝执行任务
*
* 一个线程池 core 7, max 20 , queue 50, 100个线程并发进来如何处理?
* 首先7个进入core执行,50个进queue,13个进入max执行,多余的30使用拒绝策略丢弃
*/
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
100,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());

}

public static class Thread01 extends Thread {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
System.out.println("结果:" + 10 / 2);
}
}

public static class Runable01 implements Runnable {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getId());
System.out.println("结果:" + 10 / 2);
}
}

public static class Callable01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("当前线程:" + Thread.currentThread().getId());
Integer i = 10 / 2;
System.out.println("结果:" + i);
return i;
}
}

2、线程池的七大参数

@param corePoolSize 池中一直保持的线程的数量,即使线程空闲。除非设置了 allowCoreThreadTimeOut *
@param maximumPoolSize 池中允许的最大的线程数 *
@param keepAliveTime 当线程数大于核心线程数的时候,线程在最大多长时间没有接到新任务就会终止释放, 最终线程池维持在 corePoolSize 大小 *
@param unit 时间单位 *
@param workQueue 阻塞队列,用来存储等待执行的任务,如果当前对线程的需求超过了 corePoolSize 大小,就会放在这里等待空闲线程执行。
@param threadFactory 创建线程的工厂,比如指定线程名等
@param handler 拒绝策略,如果线程满了,线程池就会使用拒绝策略

ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
100,
10,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());

运行流程:
1、线程池创建,准备好 core 数量的核心线程,准备接受任务
2、新的任务进来,用 core 准备好的空闲线程执行
(1) 、core 满了,就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队 列获取任务执行
(2) 、阻塞队列满了,就直接开新线程执行,最大只能开到 max 指定的数量
(3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自 动销毁。最终保持到 core 大小
(4) 、如果线程数开到了 max 的数量,还有新任务进来,就会使用 reject 指定的拒绝策 略进行处理 3、所有的线程创建都是由指定的 factory 创建的。
3、所有的线程创建都是由指定的 factory 创建的。

## 面试:

**一个线程池 core 7; max 20 ,queue:50,100 并发进来怎么分配的;**
先有 7 个能直接得到执行,接下来 50 个进入队列排队,在多开 13 个继续执行。现在 70 个 被安排上了。剩下 30 个默认拒绝策略。

3、常见的 4 种线程池

3.1)newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若 无可回收,则新建线程。
3.2)newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3.3)newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。
3.4)newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务 按照指定顺序(FIFO, LIFO, 优先级)执行。

4、开发中为什么使用线程池

4.1)降低资源的消耗
 通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
4.2) 提高响应速度
 因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务 的状态,当任务来时无需创建新的线程就能执行
4.3) 提高线程的可管理性
 线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来 的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使 用线程池进行统一分配