Java 教程

Java 控制語句

面向物件程式設計

Java 內建類

Java 檔案處理

Java 錯誤和異常

Java 多執行緒

Java 同步

Java 網路

Java 集合

Java 介面

Java 資料結構

Java 集合演算法

高階 Java

Java 雜項

Java API 和框架

Java 類引用

Java 有用資源

Java - 塊同步



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

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

Java 中的塊同步

Java 程式語言提供了一種非常方便的方法來建立執行緒並使用同步塊 同步 它們的作業。您將共享資源保留在此塊中。

語法

以下是 synchronized 語句的一般形式:

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

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

無同步的多執行緒示例

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

示例

package com.tutorialspoint;

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

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

   ThreadDemo( String name,  PrintDemo pd) {
      threadName = name;
      printDemo = pd;
   }
   
   public void run() {
      printDemo.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 printDemo = new PrintDemo();

      ThreadDemo t1 = new ThreadDemo( "Thread - 1 ", printDemo );
      ThreadDemo t2 = new ThreadDemo( "Thread - 2 ", printDemo );

      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   ---   5
Counter   ---   4
Counter   ---   4
Counter   ---   3
Counter   ---   3
Counter   ---   2
Counter   ---   2
Counter   ---   1
Counter   ---   1
Thread Thread - 1  exiting.
Thread Thread - 2  exiting.

塊級同步的多執行緒示例

這是同一個示例,它按順序列印計數器值,並且每次我們執行它時,它都會產生相同的結果。我們在塊上放置了 synchronized 關鍵字,以便計數器增量程式碼現在在方法執行期間根據物件被鎖定。我們使用當前物件作為鎖,將其作為引數傳遞給 synchronized 塊。

示例

package com.tutorialspoint;

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

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

   ThreadDemo( String name, PrintDemo pd) {
      threadName = name;
      printDemo = pd;
   }
   
   public void run() {
      synchronized(printDemo) {
         printDemo.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 printDemo = new PrintDemo();

      ThreadDemo t1 = new ThreadDemo( "Thread - 1 ", printDemo );
      ThreadDemo t2 = new ThreadDemo( "Thread - 2 ", printDemo );

      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.

方法級同步的多執行緒示例

這是同一個示例,它按順序列印計數器值,並且每次我們執行它時,它都會產生相同的結果。這次我們在方法上放置了 synchronized 關鍵字,以便整個方法在方法執行期間根據物件被鎖定。

示例

package com.tutorialspoint;

class PrintDemo extends Thread {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            Thread.sleep(50);
            System.out.println("Counter --- " + i );
         }
      } catch (Exception e) {
         System.out.println("Thread " + Thread.currentThread().getName()+" interrupted.");
      }
   }
   public synchronized void run() {
      printCount();
      System.out.println("Thread " + Thread.currentThread().getName() + " exiting.");
   }
}
public class TestThread {
   public static void main(String args[]) {
      PrintDemo printDemo = new PrintDemo();
      Thread t1 = new Thread(printDemo );
      Thread t2 = new Thread(printDemo );
      t1.start();
      t2.start();
      // wait for threads to end
      try {
         t1.join();
         t2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

輸出

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

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.
廣告