スレッド動作の詳解(2/7)

ここでは、スレッドの動きを少し詳しくみていきます。

  1. スレッドについて
  2. スレッドの実装方法について
  3. スレッドの同期について(1/2)
  4. スレッドの同期について(2/2)
  5. スレッドの処理順制御について
  6. スレッドの同時実行可否について
  7. デッドロックについて

2.スレッド実装方法について

スレッドの実装方法としては、以下の2通りが存在します。

  1. Threadクラスのサブクラスのインスタンスを生成し、スレッドを起動する方法
  2. Runnableインタフェースを実装したクラスを生成し、スレッドを起動する方法

以下の仕様、サンプルコードで具体例を示します。

<<サンプルコード仕様説明>>
  ・ RacingCarクラス(スレッド処理)
     車自身です。
     例では、サーキット5周を走行します。

  ・ CarRaceクラス
     車(RacingCarクラス)の初期設定、及びスタートを行います。
     例では、車を3体用意し、各々が別スレッドで処理を行い、順位を競わせます。

2-1. Threadクラスを継承する場合

Threadクラスを継承する場合には、以下の2点に注目してください。

  1. スレッド処理を行うメソッド(run)を保持するクラス(RacingCar)にThreadクラスを継承させる。
  2. 呼び出し側のクラス(CarRace)では、そのクラスをインスタンス化し、startメソッドを呼び出し、スレッドを起動させる。

■サンプルコード

2-1-1. RacingCar.java

class RacingCar extends Thread{
    private int number = 0;
    private static int round = 5;
    private static String[] printOffset = {"", "\t\t\t", "\t\t\t\t\t\t"};

    public RacingCar(int number){
        //引数の値(車番)をインスタンス変数に格納
        this.number = number;
    }

    public void run(){
        for (int i = 1; i <= round; i++){
            try{
                 //ランダムミリ秒数スリープにて差を出す
                Thread.sleep((long)(Math.random() * 1000));
                //割込み例外処理
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(printOffset[number-1] + this.number+"号車 "+i+"周目通過");
        }
        System.out.println(printOffset[number-1] + this.number+"号車 GOAL!!");
   }
}

2-1-2. CarRace.java

class CarRace{
    public static void main(String args[]){
        //Threadクラス継承のサブクラスのインスタンスを生成する
        RacingCar racingCar1 = new RacingCar(1);
        RacingCar racingCar2 = new RacingCar(2);
        RacingCar racingCar3 = new RacingCar(3);

        //生成したスレッドのインスタンスのstartメソッドを呼び出す
        //(スレッド起動)
        racingCar1.start();
        racingCar2.start();
        racingCar3.start();
    }
}

2-2. Runnableインタフェースを実装する場合

Runnableインタフェースを実装する場合には以下の2点に注目してください。

  1. スレッド処理を行うメソッド(run)を保持するクラス(RacingCar)にRunnableインタフェースを実装させる。
  2. 呼び出し側のクラス(CarRace)では、そのクラスをインスタンス化したものを引数にThreadクラスをインスタンス化し、startメソッドを呼び出し、スレッドを起動させる。

■サンプルコード

2-2-1. RacingCar.java

class RacingCar implements Runnable{
    private int number = 0;
    private static int round = 5;
    private static String[] printOffset = {"", "\t\t\t", "\t\t\t\t\t\t"};

    public RacingCar(int number){
        //引数の値(車番)をインスタンス変数に格納
        this.number = number;
    }

    public void run(){
        for (int i = 1; i <= round; i++){
            try{
                //ランダムミリ秒数スリープにて差を出す
                Thread.sleep((long)(Math.random() * 1000));
                //割込み例外処理
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(printOffset[number-1] + this.number+"号車 "+i+"周目通過");
        }
            System.out.println(printOffset[number-1] + this.number+"号車 GOAL!!");
    }
}

2-2-2. CarRace.java

class CarRace{
    public static void main(String args[]){
        //Runnableインタフェース実装のインスタンスを引数に、
        //スレッドのインスタンスを生成する
        Thread racingCar1 = new Thread(new RacingCar(1));
        Thread racingCar2 = new Thread(new RacingCar(2));
        Thread racingCar3 = new Thread(new RacingCar(3));

        //生成したスレッドのインスタンスのstartメソッドを呼び出す
        //(スレッド起動)
        racingCar1.start();
        racingCar2.start();
        racingCar3.start();
    }
}

■実行結果イメージ

実行結果
今回のレース結果は、
1位 3号車
2位 2号車
3位 1号車

となりましたが、いつもこの順位とは限りません。

※どちらの方法でも、実行結果は同じです。


まとめ

・双方の共通点
新しいスレッドを起動させるためにThreadクラスのstartメソッドを呼び出している。
・双方の相違点
サンプルソースの赤太字部分だけが相違点です。
要は、Runnable実装オブジェクトをスレッドとしてThreadクラス型オブジェクトに委譲するか、自分自身スレッドとして実行可能にしておくかだけです。
・startメソッドについて
startメソッドとは、Threadクラスのメソッドです。
どちらの方法を用いても、スレッドの起動はこのstartメソッドに記述(オーバーライド)しておけば、後はThreadクラスのstartメソッドが事を起こしてくれます。
※runメソッドを直接呼び出すことも可能ですが、その場合は、runメソッド処理が順次実行されるだけなので、スレッドにしている意味がありません。(新しいスレッドは起動しない。)

▲PageTop


  1. スレッドについて
  2. スレッドの実装方法について
  3. スレッドの同期について(1/2)
  4. スレッドの同期について(2/2)
  5. スレッドの処理順制御について
  6. スレッドの同時実行可否について
  7. デッドロックについて