1、产生死锁的四个必要条件
- 互斥条件:一个资源每次只能被一个线程使用
- 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已经获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系
2、如何避免死锁
指定获取锁的顺序,举例如下:
- 比如某个线程只有获得A锁和B锁才能对某资源进行操作,在多线程条件下,如何避免死锁?
- 获得锁的顺序是一定的,比如规定,只有获得A锁的线程才有资格获取B锁,按顺序获取锁就可
以避免死锁!!!
3、如何查看死锁
可以通过jstack 命令来进行查询,jstack命令中会显示发生了死锁的线程
4、synchronized的锁升级过程是怎样的?
从JDK1.6版本之后,synchronized本身也在不断优化锁的机制,有些情况下他并不会是一个很重量
级的锁了。优化机制包括自适应锁、自旋锁、锁消除、锁粗化、轻量级锁和偏向锁。
锁的状态从低到高依次为无锁->偏向锁->轻量级锁->重量级锁,升级的过程就是从低到高,降级在
一定条件也是有可能发生的。
【偏向锁】:在锁对象的头部中记录一下当前获取到该锁的线程ID,下次如果该线程又来获取该锁就可以直接获取了。也就是支持锁可重入。
【轻量级锁】:当两个或以上的线程交替获取锁,但没有在对象上并发的获取锁时,偏向锁升级为轻量级锁。线程采用cas的自旋方式尝试获取该锁,避免阻塞线程造成的cpu在用户态和内核态间转换的消耗。
【重量级锁】:当两个或以上的线程并发的在同一个对象进行同步时,避免无用的自选消耗cpu,轻量级锁会升级成重量级锁。
自旋锁:由于大部分时候,锁被占用的时间很短,共享变量的锁定时间也很短,所有没有必要挂起
线程,用户态和内核态的来回上下文切换严重影响性能。自旋的概念就是让线程执行一个忙循环,
可以理解为就是啥也不干,防止从用户态转入内核态,自旋锁可以通过设置-XX:+UseSpining来开
启,自旋的默认次数是10次,可以使用-XX:PreBlockSpin设置。
自适应锁:自适应锁就是自适应的自旋锁,自旋的时间不是固定时间,而是由前一次在同一个锁上
的自旋时间和锁的持有者状态来决定。
锁消除:锁消除指的是JVM检测到一些同步的代码块,完全不存在数据竞争的场景,也就是不需要
加锁,就会进行锁消除。