[英]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.