死锁:
由于资源竞争或通信问题造成的一个阻塞现象,若无外力作用无法推进下去.
当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。
条件
1 < 竞争资源 < 抢占资源的线程数
如果竞争资源为1时,不存在死锁问题,因为不是不是A线程占有就是B线程占有,不会相互等待对方释放
代码演示
import com.enjoy.demo.p1.ch1.class1.SleepTools;
/**
* @Author: BillYu
* @Description:演示普通的死锁和解决
* @Date: Created in 13:29 2019-03-15.
*
*
* 死锁:由于资源竞争或通信问题造成的一个阻塞现象,若无外力作用无法推进下去
* 1 < 竞争资源 < 抢占资源的线程数
*
*/
public class NormalDeadLock {
/**
* 第一个锁
*/
private static Object valueFirst = new Object();
/**
* 第二个锁
*/
private static Object valueSecond = new Object();
/**
* 先拿第一个锁,再拿第二个锁
*/
private static void firstToSecond() throws InterruptedException{
String threadName = Thread.currentThread().getName();
synchronized (valueFirst){
System.out.println(threadName+" get first");
SleepTools.ms(100);
synchronized (valueSecond){
System.out.println(threadName+" get second");
}
}
}
/**
* 先拿第二个锁,再拿第一个锁
*/
private static void secondToFirst() throws InterruptedException{
String threadName = Thread.currentThread().getName();
synchronized (valueSecond){
System.out.println(threadName+" get second");
SleepTools.ms(100);
synchronized (valueFirst){
System.out.println(threadName+" get first");
}
}
}
/**
* 执行先拿第二个锁,再拿第一个锁
*/
private static class TestThread extends Thread{
private String name;
public TestThread(String name){
this.name = name;
}
@Override
public void run(){
Thread.currentThread().setName(name);
try{
secondToFirst();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread.currentThread().setName("TestDeadLock");
TestThread testThread = new TestThread("SubTestThread");
testThread.start();
try{
firstToSecond();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
控制台输出:
SubTestThread get second
TestDeadLock get first
怀疑发生死锁如何排查
通过jps查询应用的id,再通过jstack id查看应用的锁的持有情况(持有的锁 等待的锁)。
解决死锁
1.保证加锁的顺序
比如对象的hashcode,可以使用System.identityHashCode() 系统提供的native方法,两个对象identityHashCode相同的概率只有千万分之一。如果对象的identityHashCode相同,可以再在外面加一个总的锁,如果不同就以identityHashCode从小到大获取锁的顺序进行。
2.ReentrantLock
尝试获取锁,直到获取到所有的锁为止,有锁竞争时释放锁。
可能会导致活锁的情况。可休眠随机时长,避免活锁的发生。
活锁
尝试拿锁的机制中,发生多个线程之间相互谦让,不断发生拿锁,释放锁的过程。
解决办法:每个线程休眠随机时长,错开拿锁的时间