我有两段代码。第一段使用同步块,它导致了死锁,这是完全可以理解的。
在第二段代码中,我试图重新创建同样的问题,但使用了 Reentrant locks
这次。但第二个代码 在某些情况下不会导致死锁。 有些情况下会出现死锁,控制台中什么也没有打印。
你能解释一下为什么吗?我是不是没有使用 Reentrant locks
正确吗?
导致死锁的代码
package com.practice.multithreading;
public class DeadlockYoutube {
public static void main(String[] args) {
final String resource1="Printer";
final String resource2="Scanner";
Runnable run1=()->{
synchronized (resource1) {
System.out.println(Thread.currentThread().getName()+" : locked-> "+resource1);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(resource2) {
System.err.println(Thread.currentThread().getName()+" : locked-> "+resource2);
}
}
};
Runnable run2=new Runnable(){
@Override
public void run() {
synchronized (resource2) {
System.out.println(Thread.currentThread().getName()+" : locked-> "+resource2);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(resource1) {
System.err.println(Thread.currentThread().getName()+" : locked-> "+resource1);
}
}
}
};
Thread thread1= new Thread(run1);
thread1.setName("Desktop");
Thread thread2=new Thread(run2);
thread2.setName("Laptop");
thread1.start();
thread2.start();
}
}
同样的代码,再入式锁止导致死锁。
package com.practice.multithreading;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//not working as expected
public class DeadlockYoutubeReentrantLocks {
public static void main(String[] args) {
final String resource1 = "Printer";
final String resource2 = "Scanner";
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
Runnable run1 = () -> {
lock1.lock();
lock2.lock();
System.out.println(Thread.currentThread().getName() + " : locked-> " + resource1);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println(Thread.currentThread().getName() + " : locked-> " + resource2);
lock1.unlock();
lock2.unlock();
};
Runnable run2 = new Runnable() {
@Override
public void run() {
lock2.lock();
lock1.lock();
System.out.println(Thread.currentThread().getName() + " : locked-> " + resource2);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.err.println(Thread.currentThread().getName() + " : locked-> " + resource1);
lock2.unlock();
lock1.unlock();
}
};
Thread thread1 = new Thread(run1);
thread1.setName("Desktop");
Thread thread2 = new Thread(run2);
thread2.setName("Laptop");
thread1.start();
thread2.start();
}
}
我试着把锁的顺序颠倒过来,但代码有时会执行得很好,而且 有时会出现僵局,控制台里什么都没有。.
请解释这种行为。
你的两段代码不是 相当.
在第一种情况下,你
在第二段代码中(使用锁)
通过第二种方式,你是降低了两个线程获取每个资源的锁的概率(线程1获取资源1的锁,线程2获取资源2的锁)。因此,这就降低了死锁的次数比例。
要让第2个片段等同于第1个片段。
Runnable run1 = () -> {
lock1.lock();
System.out.println(Thread.currentThread().getName() + " : locked-> " + resource1);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock2.lock(); //<-- Moved here
System.err.println(Thread.currentThread().getName() + " : locked-> " + resource2);
lock1.unlock();
lock2.unlock();
};
Runnable run2 = () -> {
lock2.lock();
System.out.println(Thread.currentThread().getName() + " : locked-> " + resource2);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock1.lock(); //<-- Moved here
System.err.println(Thread.currentThread().getName() + " : locked-> " + resource1);
lock2.unlock();
lock1.unlock();
};
这应该会让你的代码死锁,因为经常使用 同步.As 评论者@michalk,这两段代码都容易出现死锁。