java_读书02java核心面试知识整理

JAVA核心面试知识整理.pdf

4.1.2 使用ExecutorService、Callable、Future实现有返回结果的线程

可返回值的任务必须实现Callable接口
无返回值的任务必须实现Runnable接口
执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object
注意:get方法是阻塞的,即:线程无返回结果,get方法会一直等待

4.1.3 4种线程池

Java 里面线程池的顶级接口是 Executor,但是严格意义上讲 Executor 并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是 ExecutorService。
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

1
2
3
4
它比较适合处理执行时间比较小的任务;
corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;
keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;
采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

1
2
3
4
它是一种固定大小的线程池;corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;
阻塞队列采用了LinkedBlockingQueue,它是一个无界队列;由于阻塞队列是一个无界队列,因此永远不可能拒绝任务;
由于采用了无界队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

1
2
它只会创建一条工作线程处理任务;
采用的阻塞队列为LinkedBlockingQueue;

java newCachedThreadPool 线程池使用在什么情况下?:https://www.zhihu.com/question/23212914

handler(饱和策略,或者又称拒绝策略)
当队列和线程池都满了,即线程池饱和了,必须采取一种策略处理提交的新任务。
AbortPolicy: 无法处理新任务时,直接抛出异常,这是默认策略。
CallerRunsPolicy:用调用者所在的线程来执行任务。
DiscardOldestPolicy:丢弃阻塞队列中最靠前的一个任务,并执行当前任务。
DiscardPolicy: 直接丢弃任务。

总结
| 线程池 | 特点 | 建议使用场景 |
| — | — | — |
| newCachedThreadPool | 1、线程数无上限 2、空闲线程存活60s 3、阻塞队列 | 1、任务执行时间短 2、任务要求响应时间短 |
| newFixedThreadPool | 1、线程数固定 2、无界队列 | 1、任务比较平缓 2、控制最大的线程数 |
| newScheduledThreadPool | 核心线程数量固定、非核心线程数量无限制(闲置时马上回收) | 执行定时 / 周期性 任务 |
| newSingleThreadExecutor | 只有一个核心线程(保证所有任务按照指定顺序在一个线程中执行,不需要处理线程同步的问题) | 不适合并发但可能引起IO阻塞性及影响UI线程响应的操作,如数据库操作,文件操作等 |

使用线程池容易出现的问题
| 现象 | 原因 |
| — | — |
| 整个系统影响缓慢,大部分504 | 1、为设置最大的线程数,任务积压过多,线程数用尽 |
| oom | 1、队列无界或者size设置过大 |
| 使用线程池对效率并没有明显的提升 | 1、线程池的参数设置过小,线程数过小或者队列过小,或者是服务器的cpu核数太低 |

线程池的监控
为什么要对线程池进行监控

1
2
线程池中线程