• 线程池的常见面试问题


    • 谈谈线程池的理解? 

    线程池,是指管理一组同构工作线程的资源池,对一组线程进行统一的分配、监控、管理;线程池通过重用使用线程而不是创建新线程,可以在处理多个请求时,分摊使用直接创建和销毁线程产生的巨大资源开销。

    • 线程池的7个核心参数?

    线程池的核心参数有 核心线程数最大线程数、非核心线程的存活时间时间单位阻塞工作队列拒绝策略、ThreadFactory(线程工厂)。

    核心线程数:可理解为线程池可维护的最小线程数量,核心线程创建后不会被回收,但大于核心数量的线程,在超过存活时间后会被回收。

    最大线程数:线程池可容纳(允许创建)的最大线程数量。(核心线程数+非核心线程数)

    非核心线程的存活时间:非核心线程的空闲时间超过该存活时间,就会被回收。

    时间单位:存活时间的单位。

    阻塞工作队列:是用来存储等待执行任务的队列。

    拒绝策略:线程池的核心线程和非核心线程耗尽,工作队列也满了的时候,如果有新提交的任务,则直接采用拒绝策略。默认的拒绝策略是:ThreadPoolExecutor.AbortPolicy,丢弃任务并抛出。一共4个拒绝策略,还有三个分别是 丢弃任务不抛出异常、丢弃队列中最末尾的任务(也就是最早进入队列的最旧的任务)、由原调用线程执行该任务(谁调用,谁执行).

    ThreadFactory(线程工厂):主要用于创建线程,默认的工厂是defaultThreadFactory。

    • 线程池运行过程?

    提交一个线程任务时,线程池会分配一个空闲线程,用于执行线程任务。

    如果线程池中不存在空闲线程,那么就判断“当前存活的线程数量”是否小于核心线程数量,如果小于核心线程数,则创建一个核心线程去处理提交的线程任务。

    如果线程池的线程数量大于核心线程数,则线程池会判断工作队列是否已满,若工作队列未满,则将该任务放入工作队列,等待线程池从工作队列取出别执行。

    如果工作队列已满,则判断线程池的当前线程数是否达到最大线程数,如果未达到最大线程数,则创建一个非核心线程来执行提交的任务;若达到线程池的最大线程数量,还有新任务需要提交,则直接执行拒绝策略。

    综上:线程池的执行顺序是:核心线程、工作队列、非核心线程。

    • 常见线程池有哪些以及使用场景?

    常见线程池:

    FixedThreadPool(线程数固定的线程池)使用的队列是无界队列,LinkedBlockingQueue。使用场景:适用于CPU密集型任务,确保CPU在长期被工作线程使用情况下,尽可能少的分配线程,即适用于执行长期的任务。

    CachedThreadPool(线程数根据任务动态调整的线程池)使用的队列是,同步队列,队列容量未0;使用场景:用于并发执行大量短期的小任务。

    SingleThreadPool(单一线程的线程池,只有一个线程)使用的队列是:无界队列,使用场景:适用于串行执行任务的场景,将任务按顺序执行。

    ScheduledThreadPool(能执行定时、周期性任务的线程池)使用的队列是:DelayedWorkQueue基于堆栈结构的延迟队列,基于数组实现,初始容量为16的队列,按照延迟时间排序。使用场景:周期性执行,且需要限制线程数量的场景。

    • 为什么要使用线程池?

    因为Java支持多线程开发,也就是支持多个任务并行,但频繁的创建销毁线程比较消耗性能,通过线程池,我们可以重复使用线程,减少性能的开销。

    方便线程并发数的管理,提高响应速度,通过调用线程池的线程,从而提高响应速度。

    •  对死锁的理解?

    多个线程运行过程中,都需要获取对方线程所持有的锁,导致长期处于无限等待的状态。

    •  ReentrantLock 与 synchronized有什么区别?

    ReentrantLock和synchronized都是可重入锁(一个线程可以多次获取同一个锁);主要区别是ReentrantLock可以尝试获取锁,如果没有获取到,就可以进行别的操作,而不是无限等待下去造成死锁,更灵活;但synchronized是抢占模型,没获取到会一直等待;除了这个区别,synchronized是java提供的语法,使用后自动释放,但ReentrantLock是java代码实现的锁,使用后需要手动释放锁且支持公平锁。

    • sleep()和wait()有什么区别?
    1. 主要区别是:sleep()没有释放锁;wait()释放了锁,其他线程可是使用同步控制块或方法
    2. sleep()是Thread类的方法,wait()是Object类的方法
    3. wait()、notify()、notifyAll()只能在同步控制块或同步控制方法里使用,但sleep()可以在任何地方使用。
    4. sleep需要捕获异常,wait()不需要。
    • 乐观锁和悲观锁是什么?

    乐观锁:乐观的认为在读取数据或资源时,不会被别人修改,锁机制较为宽松。

    悲观锁:总认为数据会被别人修改,所以悲观锁在释放前,拒绝其他线程访问,悲观锁有强烈的独占和排他特性。

    • 详细说一下sychronized如何实现的?锁升级的过程了解吗?

    在JDK1.6之前,sychronized被称为重量级锁;JDK1.6之后,为了减少获得锁和释放锁带来的性能开销,引入了偏向锁和轻量级锁。底层是通过监视器monitor实现,线程通过执行monitorentry尝试获取monitor的所有权;当monitor被占用,就会处于锁定状态。默认使用偏斜锁,偏斜锁只适用于单线程的情况下,一旦出现其他线程,就会转换成轻量级锁,适用于多线程串行,一旦出现并发情况,就会进一步升级成重量级锁。

    • 产生死锁的四个条件是什么?

    资源互斥:对锁分配的资源进行排他性控制,锁在同一时刻只能被一个线程使用

    不可剥夺:线程已获得的资源在未使用完成之前,不可被剥夺。只能等待占有者自己释放。

    请求等待:线程因请求资源阻塞时,线程对已经持有的资源保持不释放。

    循环等待:线程之间的相互等待

  • 相关阅读:
    小程序变更主体公证怎么做?
    【数据结构】详解二叉树之堆
    Go语言Web开发入门指南
    只要做好充分准备,丢失的苹果设备多半可以找回来,包括AirPods
    网络编程及套接字
    shell脚本(五)函数
    竞赛选题 深度学习 机器视觉 车位识别车道线检测 - python opencv
    vscode支持c++编译
    html和css中图片加载与渲染的规则是什么?
    .sql数据库导入错误:/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */
  • 原文地址:https://blog.csdn.net/weixin_53233753/article/details/126839446