Java死锁常见原因
这里说一下简单的两个线程死锁案例,线程1先拿到了a锁,在没有释放a锁的情况下想要拿b锁,而线程2正好相反,在没有释放b锁的情况下想要去拿a锁,所以两个线程就处于阻塞状态,都在等待对方释放锁,这就造成了死锁。
看下面这个简单例子,很简单,线程1拿到a锁后睡眠了5ms,接着去拿b锁,线程2拿到b锁后睡眠了5ms,接着去拿a锁,所以目前的状态就是,线程1在等b锁,线程2在等a锁,这明显是等不到的,大家都在僵持着等待对方给自己,但是明显是不可能的,因为2个线程获取锁的第二个代码块在第一个获取锁的代码块中,所以不是不想给,是没法给。把其中一个线程第二个代码块提出来放到第一个获取锁的代码块之外,这样就不会死锁了,按例子里来说,把线程1的下面这个代码块从synchronized (a)提出来两个线程就不会死锁了,因为线程1执行完synchronized (a)后立马释放了a锁,线程2在拿到b锁,然后接着拿到a锁执行完代码块,释放b锁和a锁,此时线程1等到了b锁,这样就不会相互阻塞了。
死锁产生的4个必要条件
1、互斥:某种资源一次只允许一个进程访问,即该资源一旦分配给某个进程,其他进程就不能再访问,直到该进程访问结束。
2、占有且等待:一个进程本身占有资源(一种或多种),同时还有资源未得到满足,正在等待其他进程释放该资源。
3、不可抢占:别人已经占有了某项资源,你不能因为自己也需要该资源,就去把别人的资源抢过来。
4、循环等待:存在一个进程链,使得每个进程都占有下一个进程所需的至少一种资源。
下面的代码块用到了lambda表达式,不是很了解lambda表达式的可以看最后面的例子。摘抄自死锁的四个必要条件和解决办法
package test;
/**
* Created by Administrator on 2019\5\5 0005.
*/
public class LockTest {
public static void main(String[] args) {
Object a = new Object();
Object b = new Object();
new Thread(() -> {
synchronized (a){
System.out.println(Thread.currentThread().getName()+"已经获得a锁");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"睡眠5ms结束");
synchronized (b) {
System.out.println(Thread.currentThread().getName()+"已经获得b锁");
}
}
},"线程1").start();
new Thread(() -> {
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "已经获得b锁");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"睡眠5ms结束");
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "已经获得a锁");
}
}
},"线程2").start();
}
}
输出结果:
线程1已经获得a锁
线程2已经获得b锁
线程1睡眠5ms结束
线程2睡眠5ms结束
package test;
/**
* Created by Administrator on 2019\5\5 0005.
*/
public class LockTest {
public static void main(String[] args) {
Object a = new Object();
Object b = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (a){
System.out.println(Thread.currentThread().getName()+"已经获得a锁");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"睡眠5ms结束");
synchronized (b) {
System.out.println(Thread.currentThread().getName()+"已经获得b锁");
}
}
}
},"线程1").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (b) {
System.out.println(Thread.currentThread().getName() + "已经获得b锁");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"睡眠5ms结束");
synchronized (a) {
System.out.println(Thread.currentThread().getName() + "已经获得a锁");
}
}
}
},"线程2").start();
}
}