目录:
- 第一题. Java死锁如何避免?
- 第二题. 为什么⽤线程池?解释下线程池参数?
- 第三题. 线程池的底层⼯作原理
- 第四题. ReentrantLock中tryLock()和lock()⽅法的区别
- 第五题. Sychronized和ReentrantLock的区别?
第一题. Java死锁如何避免?
造成死锁的⼏个原因:
- ⼀个资源每次只能被⼀个线程使⽤
- ⼀个线程在阻塞等待某个资源时,不释放已占有资源
- ⼀个线程已经获得的资源,在未使⽤完之前,不能被强⾏剥夺
- 若⼲线程形成头尾相接的循环等待资源关系
这是造成死锁必须要达到的4个条件,如果要避免死锁,只需要不满⾜其中某⼀个条件即可。⽽其中前3个条件是作为锁要符合的条件,所以要避免死锁就需要打破第4个条件,不出现循环等待锁的关系。
在开发过程中:
- 要注意加锁顺序,保证每个线程按同样的顺序进⾏加锁
- 要注意加锁时限,可以针对所设置⼀个超时时间
- 要注意死锁检查,这是⼀种预防机制,确保在第⼀时间发现死锁并进⾏解决
第二题. 为什么⽤线程池?解释下线程池参数?
1、降低资源消耗;提⾼线程利⽤率,降低创建和销毁线程的消耗。
2、提⾼响应速度;任务来了,直接有线程可⽤可执⾏,⽽不是先创建线程,再执⾏。
3、提⾼线程的可管理性;线程是稀缺资源,使⽤线程池可以统⼀分配调优监控。
●corePoolSize
代表核⼼线程数,也就是正常情况下创建⼯作的线程数,这些线程创建后并不会消除,⽽是⼀种常驻线程
●maxinumPoolSize
代表的是最⼤线程数,它与核⼼线程数相对应,表示最⼤允许被创建的线程数,⽐如当前任务较多,将核⼼线程数都⽤完了,还⽆法满⾜需求时,此时就会创建新的线程,但是线程池内线程总数不会超过最⼤线程数
● keepAliveTime
、 unit
表示超出核⼼线程数之外的线程的空闲存活时间,也就是核⼼线程不会消除,但是超出核⼼线程数的部分线程如果空闲⼀定的时间则会被消除,我们可以通过setKeepAliveTime 来设置空闲时间
● workQueue
⽤来存放待执⾏的任务,假设我们现在核⼼线程都已被使⽤,还有任务进来则全部放⼊队列,直到整个队列被放满但任务还再持续进⼊则会开始创建新的线程
● ThreadFactory
实际上是⼀个线程⼯⼚,⽤来⽣产线程执⾏任务。我们可以选择使⽤默认的创建⼯⼚,产⽣的线程都在同⼀个组内,拥有相同的优先级,且都不是守护线程。当然我们也可以选择⾃定义线程⼯⼚,⼀般我们会根据业务来制定不同的线程⼯⼚
● Handler
任务拒绝策略,有两种情况,第⼀种是当我们调⽤ shutdown 等⽅法关闭线程池后,这时候即使线程池内部还有没执⾏完的任务正在执⾏,但是由于线程池已经关闭,我们再继续想线程池提交任务就会遭到拒绝。另⼀种情况就是当达到最⼤线程数,线程池已经没有能⼒继续处理新提交的任务时,这是也就拒绝
第三题. 线程池的底层⼯作原理
线程池内部是通过队列+线程实现的,当我们利⽤线程池执⾏任务时:
- 如果此时线程池中的线程数量⼩于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
- 如果此时线程池中的线程数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放⼊缓冲队列。
- 如果此时线程池中的线程数量⼤于等于corePoolSize,缓冲队列workQueue满,并且线程池中的数量⼩于maximumPoolSize,建新的线程来处理被添加的任务。
- 如果此时线程池中的线程数量⼤于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
- 当线程池中的线程数量⼤于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终⽌。这样,线程池可以动态的调整池中的线程数
第四题. ReentrantLock中tryLock()和lock()⽅法的区别
- tryLock()表示尝试加锁,可能加到,也可能加不到,该⽅法不会阻塞线程,如果加到锁则返回true,没有加到则返回false
- lock()表示阻塞加锁,线程会阻塞直到加到锁,⽅法也没有返回值
第五题. Sychronized和ReentrantLock的区别?
- sychronized是⼀个关键字,ReentrantLock是⼀个类
- sychronized会⾃动的加锁与释放锁,ReentrantLock需要程序员⼿动加锁与释放锁
- sychronized的底层是JVM层⾯的锁,ReentrantLock是API层⾯的锁
- sychronized是⾮公平锁,ReentrantLock可以选择公平锁或⾮公平锁
- sychronized锁的是对象,锁信息保存在对象头中,ReentrantLock通过代码中int类型的state标识来标识锁的状态
- sychronized底层有⼀个锁升级的过程
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!