Java-multithreading

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

Java-マルチスレッド

Javaは_マルチスレッドプログラミング言語_です。つまり、Javaを使用してマルチスレッドプログラムを開発できます。 マルチスレッドプログラムには、同時に実行できる2つ以上のパーツが含まれており、各パーツが同時に異なるタスクを処理して、コンピューターに複数のCPUがある場合に利用可能なリソースを特に最適に使用できます。

定義上、マルチタスクとは、複数のプロセスがCPUなどの共通の処理リソースを共有することです。 マルチスレッドは、マルチタスクの概念をアプリケーションに拡張し、単一のアプリケーション内の特定の操作を個々のスレッドに細分することができます。 各スレッドは並行して実行できます。 OSは、異なるアプリケーション間だけでなく、アプリケーション内の各スレッド間でも処理時間を分割します。

マルチスレッドを使用すると、同じプログラムで複数のアクティビティを同時に実行できるように記述できます。

スレッドのライフサイクル

スレッドは、ライフサイクルのさまざまな段階を経ます。 たとえば、スレッドが生成され、開始され、実行された後、終了します。 次の図は、スレッドの完全なライフサイクルを示しています。

Javaスレッド

ライフサイクルの段階は次のとおりです-

  • New -新しいスレッドは、新しい状態でライフサイクルを開始します。 プログラムがスレッドを開始するまで、この状態のままです。 また、「生まれた糸」とも呼ばれます。
  • 実行可能-新しく生成されたスレッドが開始された後、スレッドは実行可能になります。 この状態のスレッドは、タスクを実行していると見なされます。
  • 待機-時々、スレッドは待機状態に移行しますが、スレッドは別のスレッドがタスクを実行するのを待機します。 別のスレッドが実行を継続するために待機中のスレッドに信号を送る場合にのみ、スレッドは実行可能状態に戻ります。
  • Timed Waiting -実行可能なスレッドは、指定された時間間隔で時間指定された待機状態に入ることができます。 この状態のスレッドは、その時間間隔が経過するか、待機しているイベントが発生すると、実行可能な状態に戻ります。
  • * Terminated(Dead)*-実行可能なスレッドは、タスクを完了するか、他の方法で終了すると、終了状態になります。

スレッドの優先度

すべてのJavaスレッドには、オペレーティングシステムがスレッドのスケジュール順序を決定するのに役立つ優先順位があります。

Javaスレッドの優先順位は、MIN_PRIORITY(定数1)からMAX_PRIORITY(定数10)の範囲です。 デフォルトでは、すべてのスレッドに優先順位NORM_PRIORITY(5の定数)が与えられます。

優先度の高いスレッドはプログラムにとってより重要であり、優先度の低いスレッドよりも前にプロセッサ時間を割り当てる必要があります。 ただし、スレッドの優先順位は、スレッドの実行順序を保証できず、プラットフォームに大きく依存します。

実行可能なインターフェイスを実装してスレッドを作成する

クラスがスレッドとして実行されることを意図している場合、 Runnable インターフェースを実装することでこれを実現できます。 あなたは3つの基本的な手順に従う必要があります-

ステップ1

最初のステップとして、 Runnable インターフェースによって提供されるrun()メソッドを実装する必要があります。 このメソッドはスレッドのエントリポイントを提供し、このメソッド内に完全なビジネスロジックを配置します。 以下は、run()メソッドの簡単な構文です-

public void run( )

ステップ2

2番目のステップとして、次のコンストラクタを使用して*スレッド*オブジェクトをインスタンス化します-

Thread(Runnable threadObj, String threadName);

ここで、_threadObj_は Runnable インターフェイスを実装するクラスのインスタンスであり、 threadName は新しいスレッドに付けられた名前です。

ステップ3

Threadオブジェクトが作成されたら、* start()*メソッドを呼び出して起動できます。これにより、run()メソッドの呼び出しが実行されます。 以下は、start()メソッドの簡単な構文です-

void start();

新しいスレッドを作成して実行を開始する例を次に示します-

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;

   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }

   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
           //Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      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[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();

      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }
}

これは、次の結果を生成します-

出力

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

スレッドクラスを拡張してスレッドを作成する

スレッドを作成する2番目の方法は、次の2つの簡単な手順を使用して Thread クラスを拡張する新しいクラスを作成することです。 このアプローチにより、Threadクラスの利用可能なメソッドを使用して作成された複数のスレッドをより柔軟に処理できます。

ステップ1

Threadクラスで利用可能な* run()*メソッドをオーバーライドする必要があります。 このメソッドはスレッドのエントリポイントを提供し、このメソッド内に完全なビジネスロジックを配置します。 以下は、run()メソッドの簡単な構文です-

public void run( )

ステップ2

Threadオブジェクトが作成されたら、* start()*メソッドを呼び出して起動できます。これにより、run()メソッドの呼び出しが実行されます。 以下は、start()メソッドの簡単な構文です-

void start( );

これは、スレッドを拡張するために書き換えられた前述のプログラムです-

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

   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }

   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
           //Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      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[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();

      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }
}

これは、次の結果を生成します-

出力

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

スレッドメソッド

以下は、Threadクラスで使用できる重要なメソッドのリストです。

Sr.No. Method & Description
1

public void start()

別の実行パスでスレッドを開始し、このThreadオブジェクトでrun()メソッドを呼び出します。

2

public void run()

このThreadオブジェクトが別個のRunnableターゲットを使用してインスタンス化された場合、run()メソッドがそのRunnableオブジェクトで呼び出されます。

3

public final void setName(String name)

Threadオブジェクトの名前を変更します。 名前を取得するためのgetName()メソッドもあります。

4

public final void setPriority(int priority)

このThreadオブジェクトの優先度を設定します。 可能な値は1〜10です。

5

public final void setDaemon(boolean on)

trueのパラメーターは、このスレッドがデーモンスレッドであることを示します。

6

public final void join(long millisec)

現在のスレッドは2番目のスレッドでこのメソッドを呼び出し、2番目のスレッドが終了するか、指定されたミリ秒数が経過するまで現在のスレッドをブロックします。

7

public void interrupt()

このスレッドに割り込み、何らかの理由でブロックされた場合に実行を継続します。

8

public final boolean isAlive()

スレッドが生きている場合、つまり、スレッドが開始されてから実行が完了するまでの間、trueを返します。

前のメソッドは、特定のThreadオブジェクトで呼び出されます。 Threadクラスの次のメソッドは静的です。 静的メソッドの1つを呼び出すと、現在実行中のスレッドで操作が実行されます。

Sr.No. Method & Description
1

public static void yield()

現在実行中のスレッドが、スケジュールされるのを待っている同じ優先順位の他のスレッドに譲ります。

2

public static void sleep(long millisec)

現在実行中のスレッドが少なくとも指定されたミリ秒数の間ブロックするようにします。

3

public static boolean holdsLock(Object x)

現在のスレッドが指定されたオブジェクトのロックを保持している場合、trueを返します。

4

public static Thread currentThread()

現在実行中のスレッド(このメソッドを呼び出すスレッド)への参照を返します。

5

public static void dumpStack()

現在実行中のスレッドのスタックトレースを出力します。これは、マルチスレッドアプリケーションのデバッグ時に役立ちます。

次のThreadClassDemoプログラムは、Threadクラスのこれらのメソッドの一部を示しています。 Runnable を実装するクラス DisplayMessage を検討します-

//File Name : DisplayMessage.java
//Create a thread to implement Runnable

public class DisplayMessage implements Runnable {
   private String message;

   public DisplayMessage(String message) {
      this.message = message;
   }

   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}

以下は、スレッドクラスを拡張する別のクラスです-

//File Name : GuessANumber.java
//Create a thread to extentd Thread

public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }

   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

以下は、上記で定義されたクラスを利用するメインプログラムです-

//File Name : ThreadClassDemo.java
public class ThreadClassDemo {

   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();

      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      } catch (InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);

      thread4.start();
      System.out.println("main() is ending...");
   }
}

これにより、次の結果が生成されます。 この例を何度も試してみると、毎回異なる結果が得られます。

出力

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

Javaマルチスレッドの主な概念

Javaでマルチスレッドプログラミングをしている間、次の概念が非常に便利である必要があります-

  • リンク:/java/java_thread_synchronization [スレッド同期とは?]
  • リンク:/java/java_thread_communication [スレッド間通信の処理]
  • リンク:/java/java_thread_deadlock [スレッドデッドロックの処理]
  • リンク:/java/java_thread_control [主なスレッド操作]