Java多线程死锁详解及简单实例
定义
多线程死锁指的是两个或者多个线程在等待对方释放所持有的锁,从而进入了死锁状态,无法继续执行,也无法退出。
死锁产生的条件
多线程死锁产生的条件如下:
-
互斥:至少有一个资源是被独占的,如一个文件、一张表或一个锁等。
-
持有和等待:至少有一个进程正持有一个资源,并等待其他的资源。
-
非抢占性:资源不能被抢占,只有持有资源的进程才能释放它。
-
循环等待:A进程持有B进程需要的资源,B进程又持有A进程需要的资源,形成一个环路。
示例1
以下是一个简单的死锁示例:
public class DeadlockExample {
static class Friend {
private final String name;
public Friend(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public synchronized void bow(Friend bower) {
System.out.format("%s: %s 在鞠躬!%n", this.name, bower.getName());
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s 鞠躬回应!%n", this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend one = new Friend("one");
final Friend two = new Friend("two");
new Thread(new Runnable() {
@Override
public void run() { one.bow(two); }
}).start();
new Thread(new Runnable() {
@Override
public void run() { two.bow(one); }
}).start();
}
}
在执行该代码的过程中,两个线程的执行顺序可能是这样的:线程1先执行one.bow(two),然后占据这个对象锁,但是线程2也会在synchronized块内调用two.bow(one),线程2就会尝试占据two对象锁。这时候就出现了线程1等待线程2释放two对象锁,同时线程2等待线程1释放one对象锁这样的情况,从而进入了死锁状态。
示例2
以下是另一个简单的死锁示例:
public class DeadlockExample {
public static void main(String[] args) {
final Object lock1 = new Object(), lock2 = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("线程1拿到两个锁了!");
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("线程2拿到两个锁了!");
}
}
}
}).start();
}
}
在执行该代码的过程中,线程1首先拿到了lock1对象锁,然后睡眠1秒,期间线程2拿到了lock2对象锁,同时睡眠1秒。这时线程1将要去获取lock2对象锁,但是此时该锁被线程2持有,于是线程1等待线程2释放lock2对象锁;同时线程2也将要去获取lock1对象锁,但是该锁被线程1持有,线程2也会等待线程1释放lock1对象锁,于是两个线程都进入了死锁状态。
避免死锁
为了避免多线程死锁问题,可以采取以下措施:
-
只在需要的时候使用锁,加锁的代码越少,则产生死锁的几率就越小。
-
对锁加时间限制,即超时自动放弃获取锁。这样可以避免进入死锁状态。
-
使用线程池。线程池中的线程是经过预先创建的,因此可以减少线程之间因同步不能而进入死锁状态的几率。
-
避免嵌套锁。如果线程需要占有多个资源,那么应该把不同的资源获取锁的顺序设为相同的,这样可以避免不同线程获取的资源顺序不同而导致死锁的情况。
结论
避免多线程死锁是一件非常重要的事情,它可以提高代码的健壮性和稳定性。避免死锁可以通过加锁的代码越少越好、对锁加时间限制、使用线程池、避免嵌套锁等措施来实现。只要加以正确的措施,就能避免死锁的发生。
以上就是Java多线程死锁详解及简单实例的攻略,希望对大家有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java 多线程死锁详解及简单实例 - Python技术站