// 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の呼び出し」というものになるので,このケースではふさわしくない.