並行プログラミング(1)


並行プログラミングの目的

並行プログラミングの目的は二種類ある.一つは並列計算機の上で高速に計 算をするためのものである.もう一つは,逐次計算機上で動かすことを想定し ているが,自然に書くためである.Java における並列プログラミングは主に 後者を目的としている.

Java言語ではスレッド(thread, 「thread of control」(制御の糸)の短縮形) という単位で並列性を制御する.論理的に並列というのは,本当に並列に動く のではなく,一つの計算機上で時分割(time-sharing)に動くことも許す(とい うより,大多数の実装ではそうなっている)ことを意味する.スーパーコンピュー タ用の FORTRAN処理系などでは,for ループを書くと自動的に並列化するもの もあるが,Javaはこれらと違って明示的な(explicitな)並列実行の指定をおこ なっていて,スレッドを生成したところでのみ並列性が現われる.

Unix上のC言語でもプロセス(あるいはOSのスレッド)を生成して,並行プログ ラムを書くことができるが,Java言語ではライブラリではなく言語の中核部分 に並行プログラムを支援するための仕組みを入れているので,書きやすいし, OSに依存しない書き方ができる.

論理的に並列に書くと自然に書けるプログラムは次のようなものである.


新しいスレッドを取得する方法

Javaでは新しい制御のスレッドを手に入れる方法が2つある. 両方の方法で,スレッドを作るプログラムのサンプルを見てみよう.
public class ThreadSample {
  public static void main(String [] args){
    ExtnOfThread t1 = new ExtnOfThread();
    t1.start();

    Thread t2=new Thread(new ImplOfRunnable());
    t2.start();
  }
}
class ExtnOfThread extends Thread{
  public void run(){
    System.out.println("Extension of Thread running");
    try{sleep(1000);}
    catch(InterruptedException ie){return;}
    System.out.println("Extension of Thread exiting");
  }
}

class ImplOfRunnable implements Runnable{
  public void run(){
    System.out.println("Implementation of Runnable running");
    // Threadのサブクラスではないので,下のようには書けない.
    //     try{sleep(1000);}
    //catch(InterruptedException ie){return;}
    System.out.println("Implementation of Runnable exiting");
  }
}
実行結果は以下のようになるだろう.
Extension of Thread running
Implementation of Runnable running
Implementation of Runnable exiting
Extension of Thread exiting
スレッドを呼び出す側は,Thread オブジェクトを作って,そのメソッド startを呼び出す.メソッド start はスレッドが動き出すための準備をした後 で,run を呼び出す.これが,スレッドの実行の主体となる.runメソッドの 実行を終えると,スレッドの実行も終わる.

Threadクラスにはrun メソッド以外に,スレッドの実行を制御するための start,stop,sleep(ミリ秒単位での休止) というメソッドがある.Runnableイ ンタフェースで,これらのメソッドを使うには,スレッドを生成するときに記 憶しておくか,あるいはスレッドを実行中に ThreadクラスのcurrentThreadメ ソッドでスレッドを取得する必要がある.さきほどのプログラムを書き直して みる.

public class ThreadSample1 {
  public static void main(String [] args){
    ExtnOfThread1 t1 = new ExtnOfThread1();
    t1.start();

    Thread t2=new Thread(new ImplOfRunnable1());
    t2.start();
  }
}
class ExtnOfThread1 extends Thread{
  public void run(){
    System.out.println("Extension of Thread running");
    try{sleep(1000);}
    catch(InterruptedException ie){return;}
    System.out.println("Extension of Thread exiting");
  }
}

class ImplOfRunnable1 implements Runnable{
  public void run(){
    System.out.println("Implementation of Runnable running");
    Thread th=Thread.currentThread();
    try{th.sleep(1000);}
    catch(InterruptedException ie){return;}
    System.out.println("Implementation of Runnable exiting");
  }
}
このプログラムの実行結果は,
Extension of Thread running
Implementation of Runnable running
Extension of Thread exiting
Implementation of Runnable exiting
のようになる.
Threadは並行(concurrent) に実行されると言っても,多くの場合は時分割 (time-sharing)で一度には1つのThreadしか動いていない.しかし,「複数の プロセッサを載せたマシンで」,「Java処理系が複数プロセッサを使えるよう になっている(green_threadsではなくnative_threadsを使用)」場合は,実際 に複数のプロセッサ上で同時に動くこともある.センターのUnixサーバ(4プロ セッサマシン)でJava SDK 1.3 を使っている場合は,この場合に該当する.

次に進む