プログラミング学習日記

プログラミング学習時のメモ帳。

Java thread シングルスレッドとマルチスレッド

間違っている場所あったら優しく教えてね

シングルスレッドとマルチスレッド

スレッドとは処理の流れのことを表しています.
シングルスレッドとは文字通りスレッドが一つということです. スレッドが一つとは何かと言うと一つの流れの中で目処理が行われるということです. 関数をスタックにつみ順番に処理を行なっていきます.
これに対してマルチスレッドは何かと言うと複数のメソッドを同時に実行することができます. 川の上がれが複数あるようなイメージです.
ぼくは日本語では理解できないので実際にコードを書いて確認していきたいと思います.

シングルスレッド

初めにシングルスレッドを行うクラスを用意します.

class SingleThread {
    int time;
    String name;

    SingleThread(int time, String name) {
        this.time = time;
        this.name = name;
    }

    void start() {
        for (int i = 0; i < 3; i++) {
            System.out.printf("%6s\t:%d\n", name, i);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {

            }
        }
    }

}

コンストラクタでスレッドを行う時に表示する名前を指定します. timeは実行をまつ時間を示しています.
startメソッドでは, コンストラクタで指定した時間ごとに出力を行います.

シングルスレッド実行クラス

上記で示したSingleThreadを実行するクラスです

public class SingleThreadTest {
    public static void main(String[] args) {
        SingleThread hoge = new SingleThread(1000, "hoge");
        hoge.start();
    }
}

hogeという名前のインスタンスをさせて実行しています. コンストラクタで指定してstartメソッドで呼び出しています.

//実行結果
  hoge  :0  // 1秒待機
  hoge  :1  // 1秒待機
  hoge  :2  // 1秒待機

10秒ごとに待機して出力を行なっています.
今回はhogeインスタンス一つだったのでインスタンスを増やして実行してみます.

複数のシングルスレッド

シングルスレッドのインスタンスを3つ用意して実行してみます.

public class SingleThreadTest {
    public static void main(String[] args) {
        // インスタンスを作成
        SingleThread hoge = new SingleThread(1000, "hoge");
        SingleThread popo = new SingleThread(1000, "popo");
        SingleThread nyan = new SingleThread(1000, "nyan");

        // 実行する
        hoge.start();
        popo.start();
        nyan.start();
    }
}
//実行結果
  hoge  :0  //1秒待機
  hoge  :1  //1秒待機
  hoge  :2  //1秒待機
  popo  :0  //1秒待機
  popo  :1  //1秒待機
  popo  :2  //1秒待機
  nyan  :0  //1秒待機
  nyan  :1  //1秒待機
  nyan  :2  //1秒待機

start()メソッドを呼び出した順番で 0 回目 , 1 回目 , 2回目 の出力が実行されました. このシングルスレッドの場合は. hoge.start();の処理が完了してから popo.start()の関数が呼ばれ終了したらnayn.start()の関数が呼ばれています.
処理が上から順番に行われていることがわかります.
シングルスレッドは上の関数から順番に実行されると覚えておけば問題ないでしょう.
比較的わかりやすいです.

マルチスレッド

今度はマルチスレッドを実装してみたいと思います.
singleThreadクラスとの変更点はThreadクラスを継承している点と, Thread.sleep(time);メソッドがsleep(time);メソッドに変更になった点です.

class MultiThread extends Thread {
    String name;
    int time;

    public MultiThread(int time, String name) {
        this.name = name;
        this.time = time;
    }

    @Override
    public void run() {
        for (int i = 0; i < 3; i++) {
            System.out.printf("%6s\t:%d\n", name, i);
            try {
                super.sleep(time);
            } catch (Exception e) {
            }
        }
    }
}

マルチスレッドの実行クラス

こちらでやる処理はあまり変わらないです.
とりあえず一つのインスタンスで実行してみます.

public class MultiThreadTest {
    public static void main(String[] args) {
        MultiThread hoge = new MultiThread(1000, "hoge");
        hoge.start();
    }
}
//実行結果
  hoge  :0  // 1秒待機
  hoge  :1  // 1秒待機
  hoge  :2  // 1秒待機

shingleThreadとなんら代わりはありません.

複数のマルチスレッドインスタンス

スレッドの実行クラスを変更して複数のインスタンスを生成するようにします.

public class MultiThreadTest {
    public static void main(String[] args) {
        // インスタンス化
        MultiThread hoge = new MultiThread(1000, "hoge");
        MultiThread popo = new MultiThread(1000, "popo");
        MultiThread nyan = new MultiThread(1000, "nyan");
        // 実行する
        hoge.start();
        popo.start();
        nyan.start();

    }
}

3つのインスタンスを作成してスレッドを実行しています.

// 実行結果
  hoge  :0
  popo  :0
  nyan  :0  //10秒待機
  nyan  :1
  hoge  :1
  popo  :1  //10秒待機
  hoge  :2
  nyan  :2
  popo  :2  //10秒待機

このように別のスレッドで動作していることがわかります. またこの時にあるスレッドの処理が終わるまで待機させることができます. それがjoinメソッドです.

joinメソッドで処理の終了をまつ

上で用いたmultithreadクラスを再利用します. 複数のインスタンスを作ってjoinメソッドを用いて処理待ち状態を作ろうと思います.

実行クラス
public class MultiThreadTest {
    public static void main(String[] args) {
        // インスタンス化
        MultiThread hoge = new MultiThread(1000, "hoge");
        MultiThread popo = new MultiThread(1000, "popo");
        MultiThread nyan = new MultiThread(1000, "nyan");
        // 実行する
        hoge.start();
        popo.start();

        try {
            hoge.join();
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }
        nyan.start();

    }
}

joinメソッドはInteruputionExceptionを投げるメソッドなのえtry-catch文で囲ってあげなくてはあなりません.
hoge,joinが行われてるところでhogeのthreadの処理(Overrideしたrunメソッドが終わるまで処理が中断します.
またhoge.join()により中断するのはMultiThreadTestクラスのmainスレッドだけなので, popo.start()で呼び出したスレッドはこの間も動き続けています.

//実行結果
  hoge  :0
  popo  :0  //1秒待機
  hoge  :1
  popo  :1  //1秒待機
  hoge  :2
  popo  :2  //1秒待機
  nyan  :0  //1秒待機
  nyan  :1  //1秒待機
  nyan  :2  //1秒待機

hoge , popo の二つのスレッドは動いているので1秒ごとに出力をしますが. hoge.join により nyan.start(); メソッドはまだ呼ばれていないので nyan出力が冴えるのが最後になっています.

これだけ覚えればスレッドはどうにか使えそうです.
スレッド関連だと他にもRunableインターフェースの継承やスレッドセーフなど学ぶことはたくさんありそうでした.

ブログを見ていただきありがとうございました