Java中的synchronized關鍵字


當我們在程式中啟動兩個或多個執行緒時,可能出現多個執行緒試圖訪問同一資源的情況,最終由於併發問題而產生不可預測的結果。例如,如果多個執行緒試圖寫入同一個檔案,則它們可能會損壞資料,因為其中一個執行緒可能會覆蓋資料,或者當一個執行緒正在開啟同一個檔案時,另一個執行緒可能正在關閉同一個檔案。

因此,需要同步多個執行緒的操作,並確保在給定時間點只有一個執行緒可以訪問資源。這是使用稱為**監視器**的概念實現的。Java中的每個物件都與一個監視器關聯,執行緒可以鎖定或解鎖該監視器。一次只有一個執行緒可以持有監視器的鎖。

Java程式語言提供了一種非常方便的方法來建立執行緒並使用**synchronized**塊同步其任務。您可以將共享資源保留在此塊中。以下是synchronized語句的一般形式:

語法

synchronized(objectidentifier) {
   // Access shared variables and other shared resources
}

這裡,**objectidentifier** 是對物件的引用,其鎖與synchronized語句表示的監視器相關聯。現在我們將看到兩個示例,我們將使用兩個不同的執行緒列印計數器。當執行緒不同步時,它們列印的計數器值不是按順序的,但是當我們將計數器放在synchronized()塊內列印時,它會為兩個執行緒按順序列印計數器。

無同步的多執行緒示例

這是一個簡單的示例,它可能按順序列印計數器值,也可能不按順序列印計數器值,並且每次執行它時,它都會根據CPU對執行緒的可用性產生不同的結果。

示例

線上演示

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter --- " + i );
         }
      } catch (Exception e) {
         System.out.println("Thread interrupted.");
      }
   }
}
class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo PD;

   ThreadDemo( String name, PrintDemo pd) {
      threadName = name;
      PD = pd;
   }

   public void run() {
      PD.printCount();
      System.out.println("Thread " + threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " + threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {
   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
      ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );

      T1.start();
      T2.start();

      // wait for threads to end
      try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

每次執行此程式都會產生不同的結果:

輸出

Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 5
Counter --- 2
Counter --- 1
Counter --- 4
Thread Thread - 1 exiting.
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.

帶同步的多執行緒示例

這是同一個示例,它按順序列印計數器值,並且每次執行它時,它都會產生相同的結果。

示例

線上演示

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter --- " + i );
         }
      } catch (Exception e) {
         System.out.println("Thread interrupted.");
      }
   }
}

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo PD;

   ThreadDemo( String name, PrintDemo pd) {
      threadName = name;
      PD = pd;
   }

   public void run() {
      synchronized(PD) {
         PD.printCount();
      }
      System.out.println("Thread " + threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " + threadName );

      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {
   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
      ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );

      T1.start();
      T2.start();

      // wait for threads to end
      try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

每次執行此程式都會產生相同的結果:

輸出

Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 1 exiting.
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.

更新於:2020年6月23日

2K+ 瀏覽量

啟動你的職業生涯

完成課程獲得認證

開始學習
廣告