Runnable

java.lang.Runnableインターフェイスを利用してスレッドを実装する方法について説明します。

java.lang.Runnableインターフェイスは、java.langパッケージのためimport節に明示する必要はありません。

カウンタークラス
package jp.co.yourcompany.education.thread;

/**
 * 非同期処理用学習クラス
 */
public class SummaryCounter {
    private int counter = 0;

    public void inclrement( ){
        counter++;
    }

    public int getCounter(){
        return counter;
    }
}
					
Runnable実装例
package jp.co.yourcompany.education.thread;

/**
 * Runnable インターフェイスを学習するためのサンプル
 * @raita.kuwabara
 */
public class RunnableSample implements Runnable {

    /**
     * カレントスレッド名とidの整合性確認用
     */
    private int id = -1;

    /**
     * スレッドの停止時間(1000ミリ秒 = 1秒)
     */
    private static final long SLEEP_MILLIONS= 1;

    /**
     * スレッド別カウンター
     */
    private int counter = 0;

    /**
     * カウンターオブジェクト
     */
    private SummaryCounter summaryCounter = null;

    /**
     * コンストラクタ
     */
    public RunnableSample(SummaryCounter summaryCounter , int id ){
        this.summaryCounter = summaryCounter;
        this.id = id;
    }


    @Override
    public void run(){
        try {
            for( int i = 0 ; i < 5 ; i++ ){
                Thread.sleep( SLEEP_MILLIONS );
                increment();
                summaryIncrement();
                outputCounter();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * それぞれのカウントをインクリメント
     */
    private void increment(){
        counter++;
    }

    /**
     * SampleThreadクラスの全インスタンスのループ総数をインクリメントする。
     * インクリメントした数を出力する。
     */
    private  void summaryIncrement(){
        synchronized( summaryCounter ){
            summaryCounter.inclrement();
            System.out.println( Thread.currentThread().getName() + ":id[ " + id + " ] summaryCounter:" + summaryCounter.getCounter());
        }
    }

    /**
     * 出力
     */
    private void outputCounter(){
        System.out.println( Thread.currentThread().getName() + ":id[ " + id + " ] counter:" + counter);
    }

    /**
     * javaコマンドから起動されるmainメソッド
     */
    public static final void main( String[] args ){

        SummaryCounter summaryCounter = new SummaryCounter();
        int threadCount = 100;
        Thread[] threadList = new Thread[threadCount];
        for( int i = 0 ; i < threadCount ; i ++){
            threadList[ i ] = new Thread( new RunnableSample( summaryCounter, i),  "Thread" + i );
            threadList[ i ].start();
        }
    }
}
					

処理内容は、前頁のThreadのサンプル(SummaryCounterに対するsynchronized)と同じです。

実行結果
Thread3:id[ 3 ] summaryCounter:1
Thread3:id[ 3 ] counter:1
Thread2:id[ 2 ] summaryCounter:2
Thread2:id[ 2 ] counter:1
Thread0:id[ 0 ] summaryCounter:3
Thread0:id[ 0 ] counter:1
Thread1:id[ 1 ] summaryCounter:4
	:
	:
Thread99:id[ 99 ] summaryCounter:496
Thread99:id[ 99 ] counter:5
Thread97:id[ 97 ] summaryCounter:497
Thread97:id[ 97 ] counter:5
Thread96:id[ 96 ] summaryCounter:498
Thread96:id[ 96 ] counter:5
Thread98:id[ 98 ] summaryCounter:499
Thread98:id[ 98 ] counter:5
Thread94:id[ 94 ] summaryCounter:500
Thread94:id[ 94 ] counter:5
				

出力結果は、必ずしもこのように出力されるとは限りません。
Runnableをimpementsした実装クラスに持たせたidとThreadが保持しているname名の番号が一致しています。
Thread.currentThread()メソッドは、現在実行中のスレッドを返します。

RunnableとThreadによる実装の違い

このインタフェースは、アクティブな間にコードを実行したいオブジェクトが使う、共通のプロトコルを提供するために設計されています。 たとえば、RunnableはThreadクラスによって実装されます。アクティブであるということは、 スレッドが開始されて、まだ終了していない状態を意味します。

さらにRunnableは、Threadをサブクラス化せずにクラスをアクティブにする手段を提供します。 Runnableを実装するクラスは、Threadのインスタンスを生成し、 ターゲットとしてクラス自身を渡すことによりThreadをサブクラス化をしなくても実行できます。

多くの場合、Threadメソッドのうち、run()メソッドだけをオーバーライドして使用する場合は、Runnableインタフェースを使用してください。 重要これは、クラスの基本的な動作を修正または拡張するのでない限り、 そのクラスをサブクラス化することは好ましくないため、重要です。

Java8API Runnable より引用

最後の一文がRunnableとThreadの実装の違いです。run()だけの実装であればRunnableにしなさいという事です。