[英]What does it mean to have a synchronized block on a different monitor than 'this' instance?
我有以下代碼。 它有兩個對象,即MultiThreadingTest和ThreadB對象。 當我們說同步(b)時 ,它到底意味着什么? 在ThreadB完成執行之前,'main'線程能否鎖定b? 我無法理解監視對象在同步塊中的重要性。
package threads;
class MultiThreadingTest
{
public static void main(String[] args)
{
ThreadB b = new ThreadB();
b.setName("Thread B");
b.start();
synchronized(b)
{
System.out.println("Current thread : "+ Thread.currentThread().getName());
try
{
System.out.println("Waiting for b to complete...");
b.wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("Total = "+b.total );
}
}
}
class ThreadB extends Thread
{
int total;
public void run()
{
synchronized(this)
{
System.out.println("Current thread : "+Thread.currentThread().getName());
for(int i=0;i<100;i++)
{
total = total + i;
}
notify();
}
}
}
synchronized(this)
意味着你將不能夠如果另一個線程的代碼塊被引用的對象上也同步里面輸入這個代碼塊this
。
synchronized(b)
表示如果另一個線程位於同樣在b
引用的對象上的代碼塊內,則無法輸入此代碼塊。
因此他們完全一樣。 唯一的區別是用於鎖定的對象。
請注意,在Thread類型的對象上等待,同步和通知是一個非常糟糕的主意。 它會混淆事物,並會導致不必要的行為,因為其他方法(例如join())也使用Thread作為監視器。
把它想象成孩子的游戲,誰擁有[無論什么對象]可以說話。 持有監視器對象的人可以用計算術語執行。
監視器是您要鎖定的對象,在任何給定時間,只有一個線程訪問每個監視器對象的同步塊保護的代碼。 對象本身是任意的,並不會對同步有太大的影響(盡管你必須注意重新分配變量以及null
引用)。 此外,JB Nizet提出了一個關於同步Thread
對象的好處,因為許多內部VM方法都可以做到這一點,你可以導致bazaar,很難檢測到bug和死鎖。
進入不同同步塊的兩個線程鎖定在不同的監視器上將同時執行,類似於兩個獨立的人群播放/制定“誰曾經持有xxx會說話”游戲。 在鎖定this
僅僅是體現一個鎖同步,而無需創建額外的鎖定對象的簡便方法。
在你的情況, ThreadB b
是相同的對象指向作為this
從內ThreadB
類含義只有一個線程可以一次輸入您的任何定義的同步塊。 該順序高度依賴於首先運行的線程,線程調度程序甚至底層系統。
監視對象的主要原因是可以實現復雜的線程安全機制。 想象一個系統,其中每個同步塊都是單線程訪問(即在任何時候,任何線程進入同步塊將保持整個VM中的每個其他線程試圖進入同步塊)不僅會導致大量性能下降,它只是沒有意義。 如果兩個不相關的應用程序模塊沒有共享數據且從不進行交互,為什么要相互鎖定?
解決方案當然是讓一個模塊使用與另一個模塊無關/不關聯的一個(或幾個)監視器對象,因此兩者可以彼此獨立地執行(假設這是所需的行為)。
為了進一步澄清,你可以寫:
class MultiThreadingTest{
public static void main(String[] args){
ThreadB b = new ThreadB();
b.setName("Thread B");
b.start();
synchronized(b.lock){
System.out.println("Current thread : "+ Thread.currentThread().getName());
try{
System.out.println("Waiting for b to complete...");
b.lock.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Total = " + b.total );
}
}
}
class ThreadB extends Thread{
public final Object lock = new Object();
int total;
public void run(){
synchronized(lock){
System.out.println("Current thread : "+Thread.currentThread().getName());
for(int i = 0; i < 100; i++){
total = total + i;
}
lock.notify();
}
}
}
與您使用的代碼完全相同 (更好,因為它解決了與Thread.join()和其他方法的沖突)。
根據我的理解,沒有。 run()方法中的'this'對象和main()方法中的'b'對象是相同的。
因此,在線程完成執行之前,'main'線程不可能獲取鎖。
run()方法中的notify()在這種情況下似乎是多余的,因為它在方法結束時,監視器上的鎖將放棄任何方式。
PS:請查看可能已在論壇中提出的類似問題。 他們可能有助於提供額外的理解。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.