共有変数と同期
複数のスレッドが同じデータを操作する時は,予測の付かない動きをするこ
ともある.次のプログラムは,10個のスレッドが,圧力計の値を見て,安全な
ら圧力を加えるというプログラムである.
// 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();
}
}
public 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
となり,範囲を超えてしまうだろう.これを防ぐために,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();
}
}
public 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の呼び出し」というものになるので,このケースではふさわしくない.
|
アニメーション