簡體   English   中英

Java線程 - 同步代碼

[英]Java Threading - Synchronized code

為什么必須指定哪個對象鎖定了同步的代碼塊?

您不必指定哪個對象已鎖定同步方法,因為它總是被'this'鎖定(我相信)。

我有兩個問題:

  • 為什么不能用“this”以外的對象阻止非靜態方法?
  • 為什么必須指定阻塞同步代碼的對象?

我已經閱讀了SCJP for Java 6的第九章,但我仍然不清楚這一點。

我意識到這可能是一個基本問題,但我是Threading的新手。

為什么不能用“this”以外的對象阻止非靜態方法?

您可以:

public void foo() {
    synchronized (lock) {
        ...
    }
}

為什么必須指定阻塞同步代碼的對象?

因為這是語言設計者選擇設計語言的方式。 synchronized ,當在實例方法上使用時,隱含地將this用作鎖。 在塊上使用時, synchronized必須明確指定鎖。

您可以。 編碼

synchronized foo() {
    // some stuff
}

在邏輯上等於代碼

foo() {
    synchronized(this) {
        // some stuff
    }
}

我說“邏輯”因為這兩個例子生成不同的字節代碼。

如果方法foo()是靜態同步,則完成類對象。

但是,您可以創建多個同步塊,這些塊在不同對象上同步到一個類中,甚至可以創建到一個方法中。 在這種情況下,你可以使用synchronized (lock) ,其中lock不是this

foo() {
    synchronized(one) {}
    ///..........
    synchronized(two) {}
}
  1. 你可以鎖定任何對象的實例,但程序員通常使用thislocker ...
  2. 因為它限制了其他線程(代碼處理單元)對代碼部分的訪問,所以你確保整個部分在一致性中運行,並且沒有任何東西(即變量)會被另一個線程警告。

考慮:

a = 1;
a++;

螺紋一個到達第二行,你指望a = 2 ,但另一個線程執行第一線,而不是2你有a = 1的第一線和a = 2的第二個線程。 現在:

synchronized (whatever)
{
   a = 1;
   a++;
}

現在第二個線程將被阻止進入code blocksynchronized主體),直到第一個線程離開它(釋放鎖定)。

您可以指定您想要的任何對象,該對象應該在同步代碼塊上具有鎖定。 實際上,你根本不應該使用synchronize(this) (或者可能要小心,請參閱Java中的Avoid synchronized(this) )。

每個對象都有一個可以同步的鎖:

final Object lock = new Object()synchronized(lock){...}

如果要同步整個方法,則無法說明哪個對象,因此它始終是“this”對象。

synchronized foo(){....}

順便提一下,第一種鎖定方式更好。

建議不要使用this方法鎖定每個方法,因為它在大多數情況下會降低並發性。 因此,建議使用Lock Stripping ,其中只有需要保護的代碼的特定部分保存在synchronized塊中

這是一種在Java Concurrency in Practice中得到很好解釋的實踐 但請注意,只有當您具有線程的一些基本經驗時,本書才有用。

要記住一些小塊:

  • 不要過度使用同步
  • 僅在需要保護整個方法時才使用方法級別同步
  • 使用不同的鎖來保護兩個不相關的實體,這將增加並發的可能性。 或者,為了讀取或寫入兩個不相關的實體,線程將阻塞相同的鎖。

     public void incrementCounter1(){ synchronized(lockForCounter1){ counter1++; } } public void incrementCounter2(){ synchronized(lockForCounter2){ counter2++; } } 

並發教程中, Synchronized方法部分:

要使方法同步,只需將synchronized關鍵字添加到其聲明:

public class SynchronizedCounter {
private int c = 0;

public synchronized void increment() {
    c++;
}

public synchronized void decrement() {
    c--;
}

public synchronized int value() {
    return c;
}
}

如果count是SynchronizedCounter的一個實例,那么使這些方法同步有兩個影響:

  • 首先, 對同一對象的兩個同步方法的調用不可能進行交錯。 當一個線程正在為對象執行同步方法時,所有其他線程調用同一對象的同步方法(暫停執行)直到第一個線程完成對象。

  • 其次,當同步方法退出時,它會自動與同一對象的同步方法的任何后續調用建立先發生關系。 這可以保證對所有線程都可以看到對象狀態的更改。

簡而言之,這就是Java中的同步工作方式。

您不必指定哪個對象已鎖定同步方法,因為它總是被'this'鎖定(我相信)。

對於實例方法是真的,對於靜態方法,它鎖定在類對象上。

為什么不能用“this”以外的對象阻止非靜態方法?

注意:

 public synchronized void increment() {
  c++;
 }

行為相當於:

 public  void increment() {
  synchronized(this) {
     c++;
  }
 }

在這段代碼可以取代this與你希望的任何對象。

為什么必須指定阻塞同步代碼的對象?

有些人,我們稱之為關鍵,代碼塊只能按順序運行,但在不受控制的並發環境中,它可能會並行運行。 這就是存在同步機制的原因。

所以我們可以像這樣划分代碼:

  • 代碼可以安全並行運行(默認情況)
  • 必須同步的代碼(必須以某種方式標記)

該標記是通過synchronized關鍵字和相應的鎖定對象進行的。

如果你有兩個不能一起運行的不同的關鍵代碼塊,它們都將具有synchronized關鍵字,並且假設它們具有相同的鎖對象。

當第一個塊正在執行時,鎖定對象變為“鎖定”。 如果在此期間需要執行第二個塊,則該代碼塊的第一個命令是:

synchronized(lock) {

但是該鎖定對象處於鎖定狀態,因為第一個塊正在執行。 第二個塊的執行在該語句上停止,直到第一個塊完成執行,並解鎖鎖定對象的狀態。 然后第二個塊可以繼續執行(並再次鎖定鎖定對象)。

該機制稱為互斥是一種與Java編程語言無關的通用概念。

可以在此處找到“鎖定對象鎖定”過程的詳細信息。

我認為你的兩個問題實際上是一樣的。 假設你想要在多個線程之間同步一個對象a的方法,你需要一個可以與之交談的公共基本系統或通道,這實際上是對象鎖提供的,所以當你想要一個對象的方法在那里同步時不需要另一個對象鎖來執行此操作,因為您訪問自身的對象具有此鎖定,這就是設計語言的方式和原因。

同步一個塊不是同一個東西,線程可以有不同的對話基礎而不是這個對象本身,例如,你可以設置一個相同的對象作為同步塊的同步對象鎖,所以這個類的所有對象可以同步塊!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM