并发编程面试文章地址链接
内容 | 博客链接 |
---|---|
并发编程面试题之常见面试题 | https://blog.csdn.net/weixin_38251871/article/details/104658674 |
并发编程面试题之 volatile 关键字 |
https://blog.csdn.net/weixin_38251871/article/details/104667384 |
并发编程面试题之 CAS |
https://blog.csdn.net/weixin_38251871/article/details/104667406 |
并发编程面试题之锁 | https://blog.csdn.net/weixin_38251871/article/details/104667392 |
并发编程面试题之阻塞队列 | 待完成… |
并发编程面试题之 AQS |
待完成… |
并发编程面试题之 synchronized 和 ReentrantLock 的区别 |
https://blog.csdn.net/weixin_38251871/article/details/104667532 |
并发编程面试题之 CyclicBarrier、CountDownLatch、Semaphore |
https://blog.csdn.net/weixin_38251871/article/details/104677582 |
并发编程面试题之 ConcurrentHashMap |
https://blog.csdn.net/weixin_38251871/article/details/104667433 |
并发编程面试题之 synchronized 实现原理 |
https://blog.csdn.net/weixin_38251871/article/details/104667415 |
线程池的作用
线程池的主要是控制运行线程的数量, 提前创建若干个线程, 如果有任务需要处理, 线程池里面的线程就会处理任务, 处理完之后并不会销毁线程, 而是等待下一个任务. 在处理过程中将任务放入队列中, 然后在线程创建后启动这些任务, 如果线程数量超过了最大数量, 那么超出数量的线程就排队等候, 直到其他线程执行完毕后再从队列中取出任务来执行
线程池的主要特点
线程复用 :
每一个Thread
都有一个start()
方法, 当调用Thread#star()
方法启动线程的时候,JVM
会调用该类的run()
方法, 那么该类的run()
方法其实就是其实现的接口Runnable#run()
方法. 这样就可以继承Thread
类并重写, 在Thread#start()
方法中添加不断循环调用传递过来的Runnable
对象, 循环方法中不断获取Runnable
对象的是Queue
实现的, 在获取下一个Runnable
之前是阻塞的.控制最大并发数
管理线程
线程池有哪些创建方式
newSingleThreadExecutor :
创建一个单线程的线程池, 其只会用唯一的工作线程执行任务, 该线程池可以在线程异常退出时, 重新启动一个线程用来替代原来的线程继续执行下去newFixedThreadPool :
创建一个定长的线程池, 可以控制线程的最大并发数newCachedThreadPool :
创建一个可缓存的线程池, 当调用execue()
方法的时候会重用以前创建好的可用的线程, 如果有没有可用的线程, 则创建一个新的线程添加到线程池中, 如果线程在60s
没有被使用会被终止和删除newScheduledThreadPool :
创建一个定长线程池, 可以支持定时及周期性执行
线程池的优点
- 重用已存在的线程, 减少对象创建销毁的开销
- 可以有效的控制线程最大并发数, 提高系统资源的使用率, 同时避免过多资源竞争和阻塞
- 提供定时执行, 定期执行, 单线程, 控制并发数等
线程池的工作过程
- 在线程刚创建的时候, 里面是没有线程的, 任务队列是作为参数传递进来的, 当任务队列里面有任务的时候, 线程池也不会马上执行它们
- 当调用
execute()
方法添加一个任务的时候, 线程池内部操作如下:
- 当正在运行的线程小于
corePoolSize
, 那么就创建一个线程运行这个任务- 当正在运行的线程大于或等于
corePoolSize
, 那么将这个任务放入到队列中- 当队列满了, 并且正在运行的线程数量小于
maximumPoolSize
, 还是需要创建非核心线程执行这个任务- 当队列满了, 并且正在运行的线程数量大于
maximumPoolSize
, 线程池会抛出异常 RejectExecutionException- 当一个线程完成任务的时候, 它会去从队列中取出下一个任务来执行
- 当一个线程没有使用时, 超过
keepAliveTime
时, 线程池会判断, 如果当前运行的线程数量大于corePoolSize
, 那么这个线程就被停止, 所以在线程池完成所有的任务后, 它最终的大小会和corePoolSize
一致
线程池中的拒绝策略
- 当线程池中的线程使用完了, 无法再为新的任务服务时, 并且等待队列也满了, 也无法放置新的任务, 这个时候就需要拒绝策略机制合理的处理这个问题
JDK 内置的拒绝策略 :
AbortPolicy :
直接抛出异常, 阻止系统正常运行CallerRunsPolicy :
只要线程池未关闭, 该策略直接在调用者线程中运行当前被丢弃的任务DiscardOldestPolicy :
丢弃最老的请求, 也就是即将被执行的任务, 并尝试再次提交当前任务如果以上策略不能满足自己的业务, 可以扩展
RejectExecutionHandler
接口