搜尋
首頁Javajava教程Java多執行緒程式設計中synchronized關鍵字的基礎用法講解

多執行緒程式設計中,最關鍵、最關心的問題應該就是同步問題,這是一個難點,也是核心。
從jdk最早的版本的synchronized、volatile,到jdk 1.5中提供的java.util.concurrent.locks套件中的Lock介面(實作有ReadLock,WriteLock,ReentrantLock),多執行緒的實作也是一步步走向成熟化。
 
同步,它是透過什麼機制來控制的呢?第一反應就是鎖,這個在學習作業系統與資料庫的時候,應該都已經接觸到了。在Java的多執行緒程式中,當多個程式競爭同一個資源時,為了防止資源的腐蝕,給第一個存取資源的執行緒分配一個物件鎖,而後來者需要等待這個物件鎖的釋放。
 
是的,Java執行緒的同步,最關心的是共享資源的使用。
 
先來了解一些有哪些執行緒的共享資源,
從JVM了解有哪些執行緒共享的資料是需要進行協調:
1,保存在堆中的實例變數;2,保存在方法區的類別變數。
 
而在Java虛擬機器載入類別的時候,每個物件或類別都會與一個監視器相關聯,用來保護物件的實例變數或類別變數;當然,如果物件沒有實例變量,或類別沒有變量,監視器就什麼也不監視了。
 
為了實現上面的說的監視器的互斥性,虛擬機為每一個物件或類別都關聯了一個鎖(也叫隱形鎖),這裡說明一下,類別鎖也是透過物件鎖來實現的,因為在類別載入的時候,JVM會為每個類別建立一個java.lang.Class的一個實例;所以當鎖定對物件的時候,也就鎖住這個類別的類別物件。
 
另外,一個執行緒是可以對一個物件進行多次上鎖,也就對應著多次釋放;它是透過JVM為每個物件鎖提供的lock計算器,上一次鎖,就加1,對應的減1,當計算機的值為0時,就釋放。這個物件鎖是JVM內部的監視器使用的,也是由JVM自動產生的,所有程式猿就不用自己動手來加了。
 
介紹完java的同步原理後,我們進入正題,先來說說synchronized的使用,而其它的同步,將在後面的章節中介紹。
 
先來運行一個範例試試。

package thread_test; 
  
/** 
 * 测试扩展Thread类实现的多线程程序 
 * 
 */
public class TestThread extends Thread{  
  private int threadnum; 
  
  public TestThread(int threadnum) {  
    this.threadnum = threadnum;  
  } 
    
  @Override
  public synchronized void run() {  
    for(int i = 0;i<1000;i++){  
          System.out.println("NO." + threadnum + ":" + i ); 
    } 
    }  
    
    public static void main(String[] args) throws Exception {  
      for(int i=0; i<10; i++){ 
          new TestThread(i).start(); 
          Thread.sleep(1); 
      } 
    }  
}

運行結果:

NO.0:887 
NO.0:888 
NO.0:889 
NO.0:890 
NO.0:891 
NO.0:892 
NO.0:893 
NO.0:894 
NO.7:122 
NO.7:123 
NO.7:124

上面只是一個片段,說明一個問題而已。
細心的童鞋會發現,NO.0:894後面是NO.7:122,也就是說沒有按照從0開始到999。
都說synchronized可以實作同步方法或同步區塊,這裡怎麼就不行?
 
先從同步的機制來分析一下,同步是透過鎖來實現的,那麼上面的例子中,鎖定了什麼對象,或鎖定了什麼類別呢?裡面有兩個變量,一個是i,一個是threadnum;i是方法內部的,threadnum是私有的。
再來了解synchronized的運作機制:
      在java程式中,當使用synchronized區塊或synchronized方法時,標誌這個區域進行監視;而JVM在處理程序時,當有程式進入監視區域時,就會自動鎖上對像或類別。
 
那麼上面的例子中,synchronized關鍵字用上後,鎖定的是什麼呢?
當synchronized方法時,鎖定呼叫方法的實例物件本身會做為物件鎖定。本例中,10個執行緒都有自己建立的TestThread的類別對象,所以取得的對象鎖,也是自己的對象鎖,與其它執行緒沒有任何關係。
 
要實現方法鎖定,必須鎖定有共享的物件。
 
對上面的實例修改一下,再看看:

package thread_test; 
  
/** 
 * 测试扩展Thread类实现的多线程程序 
 * 
 */
public class TestThread extends Thread{  
  private int threadnum; 
  private String flag;  //标记 
    
  public TestThread(int threadnum,String flag) {  
       this.threadnum = threadnum;  
        this.flag = flag; 
    } 
    
  @Override
    public void run() {  
    synchronized(flag){ 
      for(int i = 0;i<1000;i++){  
              System.out.println("NO." + threadnum + ":" + i ); 
          }  
    } 
    }  
  
    public static void main(String[] args) throws Exception {  
      String flag = new String("flag"); 
      for(int i=0; i<10; i++){ 
          new TestThread(i,flag).start(); 
          Thread.sleep(1); 
      } 
    }  
}

也就加了一個共享的標誌flag。然後在通過synchronized區塊,對flag標誌進行同步;這就滿足了鎖定共享物件的條件。
是的,運行結果,已經按順序來了。

透過synchronized區塊,指定取得物件鎖定來達到同步的目的。那有沒有其它的方法,可以透過synchronized方法來實現呢?
 
依據同步的原理:若能取得共享物件鎖或類別鎖,可實現同步。那我們是不是可以透過共享一個類別鎖來實現呢?
 
是的,我們可以使用靜態同步方法,根據靜態方法的特性,它只允許類別物件本身才可以調用,不能透過實例化一個類別物件來調用。那麼如果得到了這個靜態方法的鎖,也就是得到這個類別鎖,而這個類別鎖都是TestThread類別鎖,及達到了取得共享類別鎖的目的。
 
實作程式碼如下:

package thread_test; 
  
/** 
 * 测试扩展Thread类实现的多线程程序 
 * 
 * @author ciding 
 * @createTime Dec 7, 2011 9:37:25 AM 
 * 
 */
public class TestThread extends Thread{  
  private int threadnum; 
    
  public TestThread(int threadnum) {  
    this.threadnum = threadnum;  
  } 
    
  public static synchronized void staticTest(int threadnum) {  
    for(int i = 0;i<1000;i++){  
      System.out.println("NO." + threadnum + ":" + i ); 
    }  
  }  
  
  public static void main(String[] args) throws Exception {  
    for(int i=0; i<10; i++){ 
      new TestThread(i).start(); 
      Thread.sleep(1); 
    } 
  }  
    
  @Override
  public void run(){ 
    staticTest(threadnum); 
  } 
}

 運作結果略,與第二個範例中相同。
 
 
以上的內容主要是說明兩個問題:同步區塊與同步方法。
1,同步區塊:取得的物件鎖是synchronized(flag)中的flag物件鎖。
2,同步方法:取得的是方法所屬的類別對象,及類別物件鎖定。
靜態同步方法,由於多個執行緒都會共享,所以一定會同步。
而非靜態同步方法,只有在單例模式下才會同步。


更多Java多執行緒程式設計中synchronized關鍵字的基礎用法講解相關文章請關注PHP中文網!


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
是否有任何威脅或增強Java平台獨立性的新興技術?是否有任何威脅或增強Java平台獨立性的新興技術?Apr 24, 2025 am 12:11 AM

新興技術對Java的平台獨立性既有威脅也有增強。 1)雲計算和容器化技術如Docker增強了Java的平台獨立性,但需要優化以適應不同雲環境。 2)WebAssembly通過GraalVM編譯Java代碼,擴展了其平台獨立性,但需與其他語言競爭性能。

JVM的實現是什麼,它們都提供了相同的平台獨立性?JVM的實現是什麼,它們都提供了相同的平台獨立性?Apr 24, 2025 am 12:10 AM

不同JVM實現都能提供平台獨立性,但表現略有不同。 1.OracleHotSpot和OpenJDKJVM在平台獨立性上表現相似,但OpenJDK可能需額外配置。 2.IBMJ9JVM在特定操作系統上表現優化。 3.GraalVM支持多語言,需額外配置。 4.AzulZingJVM需特定平台調整。

平台獨立性如何降低發展成本和時間?平台獨立性如何降低發展成本和時間?Apr 24, 2025 am 12:08 AM

平台獨立性通過在多種操作系統上運行同一套代碼,降低開發成本和縮短開發時間。具體表現為:1.減少開發時間,只需維護一套代碼;2.降低維護成本,統一測試流程;3.快速迭代和團隊協作,簡化部署過程。

Java的平台獨立性如何促進代碼重用?Java的平台獨立性如何促進代碼重用?Apr 24, 2025 am 12:05 AM

Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

您如何在Java應用程序中對平台特定問題進行故障排除?您如何在Java應用程序中對平台特定問題進行故障排除?Apr 24, 2025 am 12:04 AM

要解決Java應用程序中的平台特定問題,可以採取以下步驟:1.使用Java的System類查看系統屬性以了解運行環境。 2.利用File類或java.nio.file包處理文件路徑。 3.根據操作系統條件加載本地庫。 4.使用VisualVM或JProfiler優化跨平台性能。 5.通過Docker容器化確保測試環境與生產環境一致。 6.利用GitHubActions在多個平台上進行自動化測試。這些方法有助於有效地解決Java應用程序中的平台特定問題。

JVM中的類加載程序子系統如何促進平台獨立性?JVM中的類加載程序子系統如何促進平台獨立性?Apr 23, 2025 am 12:14 AM

類加載器通過統一的類文件格式、動態加載、雙親委派模型和平台無關的字節碼,確保Java程序在不同平台上的一致性和兼容性,實現平台獨立性。

Java編譯器會產生特定於平台的代碼嗎?解釋。Java編譯器會產生特定於平台的代碼嗎?解釋。Apr 23, 2025 am 12:09 AM

Java編譯器生成的代碼是平台無關的,但最終執行的代碼是平台特定的。 1.Java源代碼編譯成平台無關的字節碼。 2.JVM將字節碼轉換為特定平台的機器碼,確保跨平台運行但性能可能不同。

JVM如何處理不同操作系統的多線程?JVM如何處理不同操作系統的多線程?Apr 23, 2025 am 12:07 AM

多線程在現代編程中重要,因為它能提高程序的響應性和資源利用率,並處理複雜的並發任務。 JVM通過線程映射、調度機制和同步鎖機制,在不同操作系統上確保多線程的一致性和高效性。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境