并发编程面试题之线程池


并发编程面试文章地址链接

内容 博客链接
并发编程面试题之常见面试题 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 待完成…
并发编程面试题之 synchronizedReentrantLock 的区别 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接口
发布了22 篇原创文章 · 获赞 3 · 访问量 797

猜你喜欢

转载自blog.csdn.net/weixin_38251871/article/details/104675416