![](/img/trans.png)
[英]Can we Access Synchronized method and an unsynchronized method of same instance from multiple threads at the same time?
[英]Can two threads access a synchronized method at the same time?
public class Deadlock {
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"
+ " has bowed to me!%n",
this.name, bower.getName());
bower.bowBack(this);
}
public synchronized void bowBack(Friend bower) {
System.out.format("%s: %s"
+ " has bowed back to me!%n",
this.name, bower.getName());
}
}
public static void main(String[] args) {
final Friend alphonse =
new Friend("Alphonse");
final Friend gaston =
new Friend("Gaston");
new Thread(new Runnable() {
public void run() { alphonse.bow(gaston); }
}).start();
new Thread(new Runnable() {
public void run() { gaston.bow(alphonse); }
}).start();
}
}
當我運行該程序時,我得到的輸出為
阿方斯:加斯頓向我鞠躬! 加斯頓:阿方斯向我鞠躬!
那么,兩個線程可以同時訪問同步方法嗎?
兩個線程可以同時訪問同步方法嗎?
這取決於兩個線程試圖鎖定的對象實例。 兩個線程無法訪問同一對象實例上的相同synchronized
方法。 一個將獲得鎖定,另一個將阻塞,直到第一個線程離開該方法。
在您的示例中,實例方法在包含它們的對象上同步。 在這種情況下,當您調用alphonse.bow(...)
您將鎖定alphonse
對象。 gaston.bow(...)
鎖定gaston
。
您可以通過兩種方法來獲取一個對象的多個實例以鎖定同一對象。
您可以將方法設為static
並synchronized
在這種情況下,它們將鎖定類對象本身。 每個類加載器僅這些對象之一。
public static synchronized void bow(Friend bower) {
它們都可以鎖定已定義的靜態對象。 就像是:
private static final Object lockObject = new Object(); ... public void bow(Friend bower) { synchronized (lockObject) { .... } }
您的輸出可能類似於以下內容:
gaston
線程(可能)首先啟動並調用bow(alphonse)
gaston
物體並輸出: Gaston: Alphonse has bowed to me!
alphonse.bowBack(this)
。 alphonse
對象並輸出: Alphonse: Gaston has bowed back to me!
alphonse.bowBack(this)
退出,解鎖alphonse
對象。 gaston.bow(alphonse)
退出,解鎖gaston
對象。 gaston
螺紋退出。 alphonse
線程(可能)接下來開始並調用bow(gaston)
alphonse
對象並輸出: Alphonse: Gaston has bowed to me!
gaston.bowBack(this)
。 gaston
對象並輸出: Gaston: Alphonse has bowed back to me!
gaston.bowBack(this)
退出,解鎖gaston
對象。 alphonse.bow(gaston)
退出,解鎖alphonse
對象。 這可能以許多不同的順序發生。 即使稍后調用start()
方法, alphonse
線程也可以首先運行。 如果alphonse.bowBack(...)
當前正在運行,那么鎖alphonse.bow(...)
您免於遭受的唯一alphonse.bow(...)
是調用alphonse.bow(...)
。 正如@ user988052指出的那樣,由於每個線程都鎖定自己的對象,然后嘗試鎖定另一個對象,因此很容易會出現死鎖。
那么,兩個線程可以同時訪問同步方法嗎?
是和否:
是的,如果在類的不同實例上調用了該方法。
不,兩個線程不能同時在類的同一實例上調用同步方法。 即使兩個線程調用不同的方法也是如此(只要實例相同)。
我沒有詳細檢查您的代碼,但我想我知道有關如何創建死鎖的典型示例。
但是,您不應僅一次調用它來嘗試創建死鎖。
循環創建線程,極有可能導致死鎖:
for ( int i = 0; i < 1000; i++ ) {
final Friend alphonse =
new Friend("Alphonse");
final Friend gaston =
new Friend("Gaston");
new Thread(new Runnable() {
public void run() { alphonse.bow(gaston); }
}).start();
new Thread(new Runnable() {
public void run() { gaston.bow(alphonse); }
}).start();
}
請注意,您不會死鎖2000個線程:只有其中一些會死鎖。 您可以通過對程序/ JVM進行線程驗證來驗證這一點。
使用synced關鍵字,您可以鎖定實例方法的實例或靜態方法的類。 因此,在這里您可以保證最多有一個線程在給定的時間在給定的實例上執行bow或bowBack(如果一個線程在執行bow,則其他線程都不能執行bowBack,因為這兩個方法都在同一鎖上同步)...
還有一個評論:由於鎖是可重入的,一旦線程獲得了鎖,它就可以輸入在同一鎖上同步的其他方法。
如《 死鎖教程》中 所述,此代碼通常來自此代碼。
死鎖運行時,兩個線程極有可能在嘗試調用bowBack時阻塞。 兩個塊都不會結束,因為每個線程都在等待另一個退出弓。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.