1. Top
  2. Java SE
  3. スレッド

スレッド

スレッドとは

スレッドとは1つのプログラム上で動作するある特定の処理のことを言います。1つのプログラム上でいくつもの処理を同時に実行しているかのように見せたい時に使用します。このようなプログラムのことをマルチスレッドプログラムと言います。

インターネットブラウザはマルチスレッドプログラムです。画像をダウンロードしながら、音楽を聞きながら、画面をスクロールしたり、他のページを閲覧したりと言ったことができます。この場合、「画像をダウンロード」、「音楽を聞く」、「画面をスクロール」、「他のページを閲覧」と言った処理をスレッドと言うことができます。
スレッドプログラムの例
//(1)Threadクラスを継承
class ExThread1 extends Thread{
    public void run() {  //(2)スレッド実行コードをrunメソッドに記載
        for(int i = 1; i <= 10; i++) {  //(3)
            System.out.println(getName() + ":" + i);
            try {
                sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args){
        //(4)クラスExThread1のオブジェクトを生成
        ExThread1 thread1 = new ExThread1();
        ExThread1 thread2 = new ExThread1();
    
        //(5)スレッドの実行
        thread1.start();
        thread2.start();
    }
}

【実行結果】
Thread-1:1 
Thread-2:1 
Thread-1:2 
Thread-2:2 
Thread-1:3 
Thread-2:3  
Thread-1:4     // thread1オブジェクトのスレッド処理と 
Thread-2:4     // thread2オブジェクトのスレッド処理が 
Thread-1:5     // 平行して動作している。 
Thread-2:5  
Thread-1:6 
Thread-2:6 
Thread-2:7 
Thread-1:7 
Thread-2:8 
Thread-1:8 
Thread-2:9 
Thread-1:9 
Thread-2:10 
Thread-1:10 



ページの先頭へ

スレッドの優先度

スレッドは複数の処理を同時に動作させる仕組みのように思われがちですが、CPUが1つしかない状態においては、それは誤りです。スレッドとは複数の処理をあるスケジュールを元に実行し、複数の処理が同時に実行しているかのように見せる仕組みなのです。

あるスケジュールはそれぞれのスレッドが持つ優先度によって決定されます。Javaの優先度はプリエンプティブ型(preempt:取って代わる)と呼ばれています。つまり、現在実行しているスレッドより高い優先度を持ったスレッドが実行された場合は、現在実行しているスレッドはより高い優先度を持つスレッドにとって変わられるが、そうでない場合(より高い優先度を持つスレッドが実行されない場合)はスレッドが終了するか、実行不可状態になるまで現在実行されているスレッドが実行されつづけると言うものです。

同じ優先度を持つスレッドが複数あった場合、Javaはどちらのスレッドを実行するかを独断的に一つ選びます。選ばれなかったスレッドは選ばれたスレッドが終了するか実行不可になるまで実行されることはありません。AからZまで表示させる優先度が同じであるスレッド2つを実行した場合の結果は以下のようになります。

ABCD・・・XYZABCD・・・XYZ

AABBCCなどと交互に実行されるわけではありません。Javaのプリエンプティブ型決定手順に従い同じ優先度を持つスレッドは一方が終了するか実行不可状態になるまで実行されることはありません。

Javaのスレッド実行手順は以上のようですが、Javaを動作させるOSによっては異なる実行手順を持つことがあります。それはOS自身がタイムスライシングと呼ばれる同じ優先度のスレッドを交互に実行する仕組み(場合によっては優先度の低いスレッドも実行)を持っていることがあるためです。OS上でCPUのタイムスケジュールを管理し、同じ優先度を持つ複数のスレッドをほぼ均等に実行していきます。タイムスケジュール機能を持つOS上でAからZまで表示させる優先度が同じであるスレッド2つを実行した場合は以下のようになります。

AABCBCDEDFGEFG・・・

同じ、もしくは異なる優先度を持つスレッドにおいてOSに依存しないプログラマの意図したようにスレッドを動作させたい場合はsynchronized、waitメソッド、notifyAllメソッドを使用します。

Threadクラスにはスレッドの優先度に関する定数、メソッドが定義されています。

【主な定数】
戻り型
定数
説明
static int
MAX_PRIORITY
スレッドに設定できる最高優先順位10を表します。
static int
MIN_PRIORITY
スレッドに設定できる最低優先順位1を表します。
static int
NORM_PRIORITY
スレッドに設定できるデフォルト優先順位5を表します。


【主なメソッド】
戻り型
定数
説明
int
getPriority
スレッドの優先順位を返します。
void
setPriority
スレッドの優先順位を変更します。


ページの先頭へ

スレッドの作成

スレッドの作成方法は、Threadクラスを継承する方法とRunnableインタフェースを実装する方法があります。

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

【例】スレッドの作成
class DoSomething extends Thread {

    // runメソッドをオーバーライド
    public void run() {
        // ここは処理を書く

    }
}

【例】スレッドの実行
class ExThread {

    public static void main(String[] args) {

        // threadオブジェクトの生成
        DoSomething thread = new DoSomething();
    
        // スレッドを実行
        thread.start();
    }
}



Runnableインタフェースを実装してのスレッドの作成

スレッドを作成するもう1つの方法として、Runnbaleインタフェースを実装する方法があります。Runnableインタフェースにはrunメソッドのみが定義されています。以下の手順により、スレッドの作成・実行を行います。

1、スレッドを作成したいクラスでRunnableインタフェースを実装し、runメソッドの本体を定義します。
2、スレッドを実行する場合はThreadクラスのオブジェクトを生成し、その際、コンストラクタの引数にRunnbaleインタフェースを実装したクラスのオブジェクト変数を指定します。
3、Threadクラスのオブジェクトからstartメソッドを呼び出し、スレッドを実行します。

【例】スレッドの作成
class DoSomething implements Runnable {

    // runメソッドをオーバーライド
    public void run() {
        // ここは処理を書く

    }
}

【例】スレッドの実行
class ExThread {

    public static void main(String[] args) {

        // クラスのオブジェクトを生成
        DoSomething ds = new DoSomething();

        // Threadクラスのオブジェクトを生成
        Thread thread = new Thread(ds);

        // スレッドを実行
        thread.start();
    }
}


ThreadクラスとRunnableインタフェースの使い分け

スレッドを作成する方法としてどのような時にThreadクラスのサブクラスを使い、どのような時にRunnableインタフェースを使うのかと言ったことがあります。一般にスレッドを実装するクラスが別のクラス(Appletなど)のサブクラスでなければならない時にRunnableインタフェースを使用します。これはJavaではクラスの多重継承は認められていないためです。一方インタフェースは、一つのクラスに対して複数のインタフェースを実装することが可能です。

【例】コマンドライン引数に指定された値が10以上の場合、例外IllegalArgumentExceptionをスローする例です。
// ○ スレッドを実装したいクラスがThreadクラス以外のクラスを継承する必要がある場合は、
//    Runnbleインタフェースを使用する。インタフェースは複数の実装が可能。
//    
class ExThread extends Applet implements Runnable, Cloneable{
…
}

// × クラスの多重継承が認められていないため、これはできない。
class ExThread extends Applet, Thread {
…
}




ページの先頭へ