Java-thread-synchronization

提供:Dev Guides
移動先:案内検索

Java-スレッド同期

プログラム内で2つ以上のスレッドを開始すると、複数のスレッドが同じリソースにアクセスしようとし、最終的に同時実行性の問題により予期しない結果が生じる場合があります。 たとえば、複数のスレッドが同じファイル内に書き込もうとすると、スレッドの1つがデータをオーバーライドしたり、あるスレッドが同じファイルを開いている間に別のスレッドが同じファイルを閉じたりするため、データが破損する可能性があります。

そのため、複数のスレッドのアクションを同期し、特定の時点で1つのスレッドのみがリソースにアクセスできるようにする必要があります。 これは、 monitors と呼ばれる概念を使用して実装されます。 Javaの各オブジェクトは、スレッドにロックまたはロック解除できるモニターに関連付けられています。 一度に1つのスレッドのみがモニターのロックを保持できます。

Javaプログラミング言語は、*同期*ブロックを使用してスレッドを作成し、タスクを同期する非常に便利な方法を提供します。 このブロック内で共有リソースを保持します。 同期ステートメントの一般的な形式は次のとおりです-

構文

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

ここで、 objectidentifier は、同期ステートメントが表すモニターにロックが関連付けられているオブジェクトへの参照です。 次に、2つの異なるスレッドを使用してカウンターを出力する2つの例を見ていきます。 スレッドが同期されていない場合、順番に並んでいないカウンター値を出力しますが、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.