为什么代码不会总是导致死锁,试图了解可重入锁与同步块的工作原理?
Why the code is not resulting in a deadlock ALWAYS, trying to understand the working of Reentrant locks vs synchronized blocks?
我有两段代码。第一个使用同步块,它会导致完全可以理解的死锁。
在第二个代码中,我尝试重现同样的问题,但这次使用 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();
}
}
与 Reentrant Locks/not 相同的代码导致死锁
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 的锁
- 睡觉
- 获取资源 2 的锁
第二个代码中(使用锁)
- 获取资源 1 的锁
- 获取资源 2 的锁
- 睡觉
对于第二个,您正在降低两个线程为每个资源获取锁的可能性(线程 1 为资源 1 获取锁,线程 2 为资源 2 获取锁)。因此,这减少了它可能死锁的次数百分比。
要使第二个片段等同于第一个片段,
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();
};
这应该与使用 同步 的代码一样经常死锁。
由于,这两种代码都容易出现死锁。
我有两段代码。第一个使用同步块,它会导致完全可以理解的死锁。
在第二个代码中,我尝试重现同样的问题,但这次使用 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();
}
}
与 Reentrant Locks/not 相同的代码导致死锁
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 的锁
- 睡觉
- 获取资源 2 的锁
第二个代码中(使用锁)
- 获取资源 1 的锁
- 获取资源 2 的锁
- 睡觉
对于第二个,您正在降低两个线程为每个资源获取锁的可能性(线程 1 为资源 1 获取锁,线程 2 为资源 2 获取锁)。因此,这减少了它可能死锁的次数百分比。
要使第二个片段等同于第一个片段,
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();
};
这应该与使用 同步 的代码一样经常死锁。
由于