Deep Side of Java〜Java 言語再入門 第4回 〜 アプレット、スレッド、AWT

スレッドの使い方

スレッドの実例〜不死身のスレッド






スレッドの使い方

スレッドの実例〜不死身のスレッド

調査した感じでは、スレッドの生成コストは低いようである。だから敢えて「不死身のスレッド」を作り、一旦生成したスレッドは終了させずに使い回す必要はなさそうである。しかし、これをやってみよう。まず、スレッドを生成し管理するマネージャである。紙幅の関係上、例外処理をサボっているが、適当に補われたい。

/* Factory Method with Dynamic Loading */
public class ThreadManager {
     private Vector usedPool;  /* 現在使用中のスレッド */
     private Vector freePool;  /* 現在手空きのスレッド */
     private Class generateClass;  /* 生成するクラスのメタクラス */
     private String className;    /* 生成するクラスのクラス名 */

     /* 常識的な動的ローディングのコンストラクタ */
     public ThreadManager( String genClass ) throws Exception {
          className = genClass;
          usedPool  = new Vector();
          freePool  = new Vector();
          generateClass = Class.forName( genClass );
     }

     private UndeadThread getThreadInstance( ) throws Exception {
          UndeadThread t = (UndeadThread)generateClass.newInstance();
          t.setManager( this );
          return t;
     }

     public UndeadThread getThread( ) throws Exception {
          UndeadThread t;
          synchronized( usedPool ) {
              if( freePool.isEmpty() ) {
                   t = getThreadInstance();
                   usedPool.add( t );
              } else {
                   t = (UndeadThread)freePool.elementAt( 0 );
                   freePool.removeElementAt( 0 );
                   usedPool.add( t );
              }
          }
          return t;
     }

     /* UndeadThread がスレッド実行コンテキストから外れる時に */
     /* 呼び出されて freePool に蓄えられる。*/
     public synchronized void endNotify( UndeadThread t ) {
          synchronized( usedPool ) {
              for( int i = 0; i < usedPool.size(); i++ ) {
                   if( t == usedPool.elementAt( i ) ) {
                        usedPool.removeElementAt( i );
                        freePool.add( t );
                        return;
                   }
              }
          }
     }
}

「不死身のスレッド」の定義は次のよう。これを継承して action メソッドに好きなような処理をさせれば良い。

public abstract class UndeadThread extends Thread {
    private ThreadManager creator;
    final static int BEFORE_RUN  = 0;
    final static int RUNNING     = 1;
    final static int RERUN_WAIT  = 2;
    private int status = BEFORE_RUN;
    Object StatusLock = new Object;  /* status のロックのために使う */

    /* アプレットから利用する場合には、interrupt() が使えない。その対策込 */
    public final static boolean APPLET_MODE = true;
    public final static boolean INTERRUPT_MODE = false;
    private static boolean appletMode = INTERRUPT_MODE;

    public final static void setAppletMode( boolean m ) { 
        appletMode = m;
    }

    public final void setManager( ThreadManager tm ) { 
        creator = tm; 
    }

    /* アプレットではこのメソッドを使って、現在の状態をチェック */
    public final boolean canContinue( ) {
        if( status == RUNNING ) return true;
        return false;
    }

    /* スレッドをスタートするにはこのメソッドを使う */
    /* これを継承して適当な前処理をつけても良かろう */
    public final void startAction() {
        synchoroized( statusLock ) {
            switch( status ) {
            case BEFORE_RUN:
                start();
                break;
            case RERUN_WAIT:
                if( ! appletMode ) {
                    interrupt();
                } else {
                    status = RUNNING; 
                }
                break;
            }
        }
    }

    /* 「不死身」な本体 */
    public final void run() {
        synchronized(statusLock) { status = RUNNING; }
        while( true ) {
            try {
                if( status == RUNNING ) {
                    action();
                    synchronized( statusLock ) { 
                        status = RERUN_WAIT; 
                    }
                    stopThread();
                } else {
                    while( status == RERUN_WAIT ) {
                        Thread.sleep( 200L );
                    }
                }
            } catch( Exception e ) {
                synchornized( statusLock ) {
                    if( status == RUNNING ) {
                        status = RERUN_WAIT;
                        stopThread();
                    } else if( status == RERUN_WAIT ) {
                        status = RUNNING;
                    }
                }
                if( ! e instanceof InterruptedException ) {
                    e.printStackTrace();
                }
            }
        }
    }

    /* マネージャに終了を通知する内部メソッド */
    /* これを継承して適当な後処理をつけても良かろう */
    private void stopThread( ) {
        if( creator != null ) {
            creator.endNotify( this );
        }
    }

    /* 「不死身スレッド」を「止める」ためのインターフェイス */
    public final void stopAction() {
        synchronized( statusLock ) {
            if( status == RUNNING ) {
                if( ! appletMode ) {
                    interrupt();
                } else {
                    status = RERUN_WAIT;
                }
            }
        }
    }

    /* 面白い作業をさせる抽象メソッド */
    public abstract void action() throws InterruptedException;
}



copyright by K.Sugiura, 1996-2006