Okapi Project

Thread (すれっど)

バージョン
2003 年 09 月 10 日 Ver.1.1
作成者
T.Hirata ( Xware )

目的

同時に複数の処理を制御したい。

Thread ってなに?

スレッドとは、ソースを連続的に実行する流れです。

Java プログラムが実行されると、1つのスレッドが生成されます。さらに、そのスレッドから別のスレッドを起動することが出来ます。このようにして、一つのプログラム中に複数のスレッドを持ったものを、マルチスレッドと呼びます。

通常、マルチスレッドを行うためには、メモリ領域や CPU 時間などのコンピュータ上の資源の割り当てなどの処理を実装しなければならないなど多くの手間がかかりますが、Java ではそれらの処理をJavaVM が行うため、基本的な処理を実装するのみでマルチスレッドを実現することが出来ます。

Thread の説明

スレッドを作成するには Thread オブジェクトとして作成して実行しますが、これには2つの作成方法があります。

  1. Thread クラスを継承して run( ) メソッドをオーバーライドする

    スレッドは通常 Thread クラスかそのサブクラスのオブジェクトとして生成・実行されます。 そこで実際に実行される処理は run( ) メソッドであるため、スレッドを作る場合には run( ) メソッドをオーバーライドして、実行する処理を記述します。
  2. Runnable インターフェースを implements するクラスを宣言して run( ) メソッドを実装する

    Java は単一継承の言語であるため一つのスーパークラスしか持てず、複数のクラスは継承することはできないため、すでにクラスを継承しているサブクラスをスレッドとして実行したい場合は Runnable インタフェースを実装します。

Thread の使い方

上記で説明した作成方法で実際にスレッドの作成を行います。

  1. Thread クラスを継承して run( ) メソッドをオーバーライドする
    class Test extends Thread {        //スレッドクラスを継承する
    	public void start() {
    		System.out.println("-- Start --");
    		super.start();
    	}
    
    	public void run() {          //スレッドで実行する処理を記述
    		System.out.println("-- run --");
    for (int i=0; i <= 5; i++) {
    System.out.println("Count: " + i); }
    System.out.println("-- run end --");
    }
    } class TestMaint {             //メイン処理
                          //Threadクラスを継承したオブジェクトを生成・実行
    public static void main(String[] args) { Test thread = new Test(); System.out.println("-- Thread New --"); thread.start(); } }

    上記の処理結果は以下のようになります。

    -- Thread New --
    -- Start --
    -- run --
    Count: 0
    Count: 1
    Count: 2
    Count: 3
    Count: 4
    Count: 5
    -- run end --
  2. Runnable インターフェースを implements するクラスを宣言して run( ) メソッドを実装する
    import java.io.*;
    class TestA implements Runnable { public void run() { for (int i=0; i <= 5; i++) {
    System.out.println("TestA: " + i); }
    } } class TestB implements Runnable { public void run() {
    for (int i=5; i >= 0; i--) { System.out.println(" TestB: " + i); } } } class TestMain {
    public static void main(String[] args) {
    // ランナブルクラスのインスタンス化
    TestA testRunA = new TestA();
    TestB testRunB = new TestB();
    System.out.println("ランナブルクラスのインスタンス化終了");
    // スレッドのインスタンス化
    Thread TestA = new Thread(testRunA);
    Thread TestB = new Thread(testRunB);
    System.out.println("スレッドへの受け渡し終了"); // スレッドの開始 TestA.start(); TestB.start();
    System.out.println("スレッドをスタート");
    } }

    上記の処理結果は以下のようになります。

    ランナブルクラスのインスタンス化終了
    スレッドへの受け渡し終了
    スレッドをスタート
    TestA: 0
    TestB: 5
    TestA: 1
    TestB: 4
    TestA: 2
    TestB: 3
    TestA: 3
    TestB: 2
    TestA: 4
    TestB: 1
    TestA: 5
    TestB: 0

ポイント

ヒント

synchronized の利用

Thread クラス、Runnable インターフェースを利用し新たな、スレッドを作成し並列処理を行なうことが出来ます。しかし、並列処理の中で、同じファイルへのアクセスなどのように、同時に処理を行なうことが出来ない処理もあります。その場合、synchronized キーワードを使って排他処理を行なうことが出来ます。

次のように書くことで実現します。メソッドに排他処理をつけることによって、このメソッドは同時に多数から呼び出されることはありません。必ず排他がかかります。

public synchronized void test(){
    List list = new Stack();
    list.add("ABC");
    list.add("BCD");
    list.add("CDE");
	
    Iterator iter = list.iterator();

    while(iter.hasNext()){
        System.out.println(iter.next());
    }		
}

volatile の利用

上記で、synchronized は、クラス・メソッドに対して他処理からの呼び出しを防ぐものでしたが、volatile は変数に対して指定します。volatile に指定された変数はメモリーからのロードと格納のタイミングについて制限がかけられます。
 以下が volatile を利用した簡単なプログラムの例です。

public class TestA {
    volatile int a;

    public TestA(int a) {
        this.a = a;
    }

    public void testA() {

        for (int i = 0; i < 5; i++) {
            a = a + 2;
        }
        System.out.println("計算結果は「" + a + "」になります");
    }
}

上記のように記述することによって変数「int a」は、複数の thread の処理によってその値に矛盾が生じるのを防ぐことが出来ます。

関連


Copyright © 2003 - 2006 Okapi Project All Rights Reserved.