// pressureを Runnableの実装として定義 class pressure implements Runnable{ // 圧力が安全圏内なら加える static void RaisePressure(){ // 現在の圧力が制限値よりも15を超して少ないなら int pval=p.pressureGauge; if(pval < p.safetyLimit-15){ // わざと 100ms(0.1秒)待つ try{ Thread.sleep(100); } catch(Exception e){} // 圧力を15加える p.pressureGauge+=15; System.out.println("pval="+pval+", p.pressureGauge="+p.pressureGauge); } else{ System.out.println("Failed adding pressure"); } } // pressureのインスタンスに対して startするとここが呼ばれる. public void run(){ RaisePressure(); } } class p{ // pクラスの静的変数(クラス変数)なのでプログラム全体から共有される // 圧力値 static int pressureGauge=0; // 圧力の制限値 static final int safetyLimit=20; public static void main(String[] args){ Thread [] ths=new Thread[10]; int i; // 10個の Threadを作り,次々と作成 for(i=0;i<10;i++){ ths[i]=new Thread(new pressure()); ths[i].start(); } // すべてのスレッドが終了するのを待つ try{ for(i=0;i<10;i++) ths[i].join(); } catch (Exception e){} System.out.println("gauge reads "+pressureGauge+", safe limit is 20"); } }これを実行すると,
pval=0, p.pressureGauge=15 pval=0, p.pressureGauge=30 pval=0, p.pressureGauge=45 pval=0, p.pressureGauge=60 pval=0, p.pressureGauge=75 pval=0, p.pressureGauge=90 pval=0, p.pressureGauge=105 pval=0, p.pressureGauge=120 pval=0, p.pressureGauge=135 pval=0, p.pressureGauge=150 gauge reads 150, safe limit is 20となり,範囲を超えてしまうだろう.
この例では,値のチェックをした後でわざとsleepしたので,確実に問題が起きた わけだが,sleepを入れなくても,100回に1回あるいは1万回に1回位でで問題が起 きることがあり得る.
これを防ぐために,Java言語では相互排 他(mutual exclusion)を実現するためのsynchronized というキーワードを用 意してある.この使い方は,メソッドにつける.ブロックにつけるなどいろい ろある.先ほどの例では,
// pressureを Runnableの実装として定義 class pressure implements Runnable{ // 圧力が安全圏内なら加える synchronized static void RaisePressure(){ // 現在の圧力が制限値よりも15を超して少ないなら int pval=p.pressureGauge; if(pval < p.safetyLimit-15){ // わざと 100ms(0.1秒)待つ try{ Thread.sleep(100); } catch(Exception e){} // 圧力を15加える p.pressureGauge+=15; System.out.println("pval="+pval+", p.pressureGauge="+p.pressureGauge); } else{ System.out.println("Failed adding pressure"); } } // pressureのインスタンスに対して startするとここが呼ばれる. public void run(){ RaisePressure(); } } class p{ // pクラスの静的変数なのでプログラム全体から共有される // 圧力値 static int pressureGauge=0; // 圧力の制限値 static final int safetyLimit=20; public static void main(String[] args){ Thread [] ths=new Thread[10]; int i; // 10個の Threadを作り,次々と作成 for(i=0;i<10;i++){ ths[i]=new Thread(new pressure()); ths[i].start(); } // すべてのスレッドが終了するのを待つ try{ for(i=0;i<10;i++) ths[i].join(); } catch (Exception e){} System.out.println("gauge reads "+pressureGauge+", safe limit is 20"); } }のようにRaisePressureにsynchronized というキーワードを付けると,同じク ラスのオブジェクトが,RaisePressureを同時に実行するのを防ぐことができ る.
メソッドRaisePressureが static になっていないと,synchronizedにより, 「同時には実行しない」単位が,「同じインスタンスに対するメソッド RaisePressureの呼び出し」というものになるので,このケースではふさわしくない.