[英]Why no deadlock on the same object in this program - Java Multithreading
我有以下三节课。 Main,两个线程和方法同步的Obj
public class DeadLocks {
public static void main(String[] args) {
SyncObj so = new SyncObj();
ThreadObj to = new ThreadObj(so);
ThreadObj1 to1 = new ThreadObj1(so);
to.start();
to1.start();
}
}
class SyncObj {
synchronized void foo() {
System.out.println("Foo Started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bar();
}
synchronized void bar() {
System.out.println("bar started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
foo();
}
}
class ThreadObj1 extends Thread {
SyncObj so;
public ThreadObj1(SyncObj so) {
this.so = so;
}
@Override
public void run() {
so.bar();
}
}
class ThreadObj extends Thread {
SyncObj so;
public ThreadObj(SyncObj so) {
this.so = so;
}
@Override
public void run() {
so.foo();
}
}
在上面的代码中,我在同一个对象上调用了同步方法。 两个方法同时执行和调用,不存在死锁情况。 谁能解释一下为什么? 抱歉问了这么愚蠢的问题。
据我所知,您在这两种情况下都使用相同的对象( so
)。 所以没有死锁的情况。 您需要锁定两个或多个对象,其中每个临界区都需要与它持有的锁不同的锁。 另一个锁由“另一个”线程持有。
令人困惑,这将启发:“ https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html ”
在您描述的场景中,您never ever deadlock
。 在这种情况下,只有一个so
正被共享,并且正在与同步。
我举个例子来说明一下:
假设安迪和桑迪正在玩两个足球B1和B2 。
现在进一步假设 Andy 和 Sandy 分别拥有球B1和B2 。 例如,安迪有球B1 ,桑迪有球B2 。
现在他们设计了一个游戏,其中每个人都需要两个球。 现在 Sandy 也想要B1球,同时,Andy 想要B2 球。
并且他们两个都不能放弃他们持有的球。 安迪不会放弃B1 ,反之亦然。
So both of them cannot continue and are stuck. We call this a deadlocked situation.
希望这个例子有帮助。 您可以发挥您的想象力将比赛中的球数增加到 3 或 4 个(依此类推……)和/或增加球员人数。
您不会遇到死锁,因为您的程序不满足形成它的四个必要条件中的两个:
您至少需要两个资源“A”和“B”才能形成死锁。 一个线程应该抓取“A”并尝试抓取“B”,而另一个线程应该抓取“B”并尝试抓取“A”。
我不知道你为什么期望这里会出现僵局。 确实只有一个对象可以访问同步部分,但是它可以随心所欲地访问。 您可以修改代码以使其清楚:
public class DeadLocks {
public static void main(String[] args) {
SyncObj so = new SyncObj();
ThreadObj to = new ThreadObj(so);
ThreadObj1 to1 = new ThreadObj1(so);
to.start();
to1.start();
}
}
class SyncObj {
synchronized void foo(String msg) {
System.out.println("Foo Started: " + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bar(msg);
}
synchronized void bar(String msg) {
System.out.println("bar started: " + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
foo(msg);
}
}
class ThreadObj1 extends Thread {
SyncObj so;
public ThreadObj1(SyncObj so) {
this.so = so;
}
@Override
public void run() {
so.bar("TO1");
}
}
class ThreadObj extends Thread {
SyncObj so;
public ThreadObj(SyncObj so) {
this.so = so;
}
@Override
public void run() {
so.foo("TO");
}
}
您可以看到以下输出:
Foo Started: TO
bar started: TO
Foo Started: TO
bar started: TO
Foo Started: TO
bar started: TO
您可以将 'synchronized' 视为 lock(this),其中 'this' 是一个 SyncObj 实例。 因此只有一个锁,不可能获得死锁。
虽然其他人已经指出只有当你有两个资源时才会发生死锁,其中每个线程锁定一个然后等待另一个,但我认为缺少一个关键点,你的整个困惑可能来自:
方法上的synchronize
不会为该特定方法创建锁,而是为其所属的整个对象创建锁。 因此,您的课程相当于:
class SyncObj {
void foo() {
synchronized(this) {
System.out.println("Foo Started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bar();
}
}
void bar() {
synchronized(this) {
System.out.println("bar started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
foo();
}
}
}
现在应该更清楚了,为什么你没有陷入僵局。
您可以通过引入两种资源(每个方法一个)来轻松修改代码,使其容易出现死锁:
class SyncObj {
private Object foolock = new Object();
private Object barlock = new Object();
void foo() {
synchronized(foolock) {
System.out.println("Foo Started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bar();
}
}
void bar() {
synchronized(barlock) {
System.out.println("bar started");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
foo();
}
}
}
使用单个实例不可能发生死锁,因为同一个对象的两个线程不能访问多个同步方法。 在上面的例子中,如果线程 1 正在访问 foo 方法。 线程 2 不能访问 foo 或 bar 方法。 直到线程 1 完成它的任务
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.