工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> Java

Javaマルチスレッド完全ガイド:効率的な並行プログラミング

マルチスレッドとは

Javaはマルチスレッドプログラミング言語であり、複数のスレッドを持つプログラムを開発できます。マルチスレッドプログラムは、同時に実行可能な2つ以上の部分を含み、それぞれが異なるタスクを同時に処理するため、特にマルチCPU環境では利用可能なリソースを最適に活用できます。

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

マルチスレッドにより、同一プログラム内で複数のアクティビティを同時並行的に進行させる記述が可能になります。

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

スレッドはその生涯で様々な段階を経ます。例えば、スレッドは生成され、開始され、実行され、そして終了します。以下の図はスレッドの完全なライフサイクルを示しています。

Javaマルチスレッド完全ガイド:効率的な並行プログラミング

ライフサイクルの段階は以下の通りです:

スレッドの優先度

すべてのJavaスレッドには優先度があり、OSがスレッドのスケジューリング順序を決定する際の指針となります。

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

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

Runnableインターフェースによるスレッド作成

クラスをスレッドとして実行する意図がある場合、Runnableインターフェースを実装することで実現できます。以下の3つの基本ステップに従ってください。

ステップ1

最初のステップとして、Runnableインターフェースが提供するrun()メソッドを実装します。このメソッドはスレッドのエントリーポイントとなり、完全なビジネスロジックをこのメソッド内に記述します。run()メソッドのシンプルな構文は以下の通りです。

public void run()

ステップ2

2番目のステップとして、以下のコンストラクタを使用してThreadオブジェクトをインスタンス化します。

Thread(Runnable threadObj, String threadName);

ここで、threadObjはRunnableインターフェースを実装したクラスのインスタンス、threadNameは新しいスレッドに与える名前です。

ステップ3

Threadオブジェクトが作成されたら、start()メソッドを呼び出して開始します。これによりrun()メソッドの呼び出しが実行されます。start()メソッドのシンプルな構文は以下の通りです。

void start();

サンプル

新しいスレッドを作成して実行する例です。

Live Demo
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);
                // スレッドを少しスリープ
                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.

Threadクラスを継承したスレッド作成

スレッドを作成する2番目の方法は、Threadクラスを継承した新しいクラスを作成することです。このアプローチは、Threadクラスで利用可能なメソッドを使用して複数のスレッドを処理する際により柔軟性があります。

ステップ1

Threadクラスで利用可能なrun()メソッドをオーバーライドする必要があります。このメソッドはスレッドのエントリーポイントとなり、完全なビジネスロジックをこのメソッド内に記述します。

public void run()

ステップ2

Threadオブジェクトが作成されたら、start()メソッドを呼び出して開始します。

void start();

サンプル

前のプログラムをThreadクラス継承で書き直した例です。

Live Demo
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);
                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クラスの主要メソッド

Threadクラスで利用可能な重要なメソッドの一覧です。

番号メソッドと説明
1public void start()
スレッドを別の実行パスで開始し、このThreadオブジェクトでrun()メソッドを呼び出します。
2public void run()
このThreadオブジェクトが別のRunnableターゲットでインスタンス化された場合、そのRunnableオブジェクトでrun()メソッドが呼び出されます。
3public final void setName(String name)
Threadオブジェクトの名前を変更します。名前取得用のgetName()メソッドもあります。
4public final void setPriority(int priority)
このThreadオブジェクトの優先度を設定します。取りうる値は1〜10です。
5public final void setDaemon(boolean on)
trueを指定すると、このスレッドをデーモンスレッドとして指定します。
6public final void join(long millisec)
現在のスレッドがこのメソッドを別のスレッドで呼び出し、そのスレッドが終了するか、指定ミリ秒が経過するまでブロックします。
7public void interrupt()
このスレッドを割り込み、何らかの理由でブロックされていた場合に実行を継続させます。
8public final boolean isAlive()
スレッドが開始済みだがまだ完了していない場合(生存中)にtrueを返します。

上記メソッドは特定のThreadオブジェクトで呼び出されます。以下のThreadクラスのメソッドは静的メソッドであり、現在実行中のスレッドに対して操作を行います。

番号メソッドと説明
1public static void yield()
現在実行中のスレッドを、スケジューリングを待っている同じ優先度の他のスレッドに譲ります。
2public static void sleep(long millisec)
現在実行中のスレッドを、指定ミリ秒以上ブロックします。
3public static boolean holdsLock(Object x)
現在のスレッドが指定オブジェクトのロックを保持している場合にtrueを返します。
4public static Thread currentThread()
現在実行中のスレッド(このメソッドを呼び出したスレッド)への参照を返します。
5public static void dumpStack()
現在実行中のスレッドのスタックトレースを出力します。マルチスレッドアプリケーションのデバッグに有用です。

スレッドメソッドのデモ

以下のThreadClassDemoプログラムは、Threadクラスのいくつかのメソッドを示しています。DisplayMessageクラスはRunnableを実装します。

// ファイル名: DisplayMessage.java
public class DisplayMessage implements Runnable {
    private String message;
    public DisplayMessage(String message) { this.message = message; }
    public void run() {
        while(true) { System.out.println(message); }
    }
}

Threadクラスを継承した別のクラス:

// ファイル名: GuessANumber.java
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.**");
    }
}

メインプログラム:

// ファイル名: 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

  1. C++マルチスレッド完全ガイド:効率的な並行プログラミング
  2. Java演算子をマスター:種類、構文、実践例
  3. Javaコメント:種類、使い方、ベストプラクティス
  4. Java拡張forループをマスター:構文、例、ベストプラクティス
  5. Java文字列をマスター:生成、メソッド、ベストプラクティス
  6. Javaインターフェース完全ガイド:概念、実装、ベストプラクティス
  7. Java無名インナークラス完全ガイド:定義、構文、実践例
  8. Javaのtry-with-resourcesをマスターする:自動リソース管理の仕組みと活用法
  9. Javaアノテーション完全ガイド:種類、配置場所、実践例
  10. Javaアサーション完全ガイド:バグ早期発見とコード信頼性の向上
  11. Java Vectorの理解:使い方、特徴、ArrayListとの比較