共有変数と同期
複数のスレッドが同じデータを操作する時は,予測の付かない動きをするこ
ともある.次のプログラムは,10個のスレッドが,圧力計の値を見て,安全な
ら圧力を加えるというプログラムである.
// pressureを Threadのサブクラスとして定義
// Threadによって動く実体とする
class pressure extends Thread{
// 圧力が安全圏内なら加える
static void RaisePressure(){
// 現在の圧力が制限値よりも15を超して少ないなら
int pval=p.pressureGauge;
if(pval < p.safetyLimit-15){
// わざと 100ms(0.1秒)待つ
try{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){
pressure [] p1=new pressure[10];
int i;
// 10個の Threadを作り,次々と作成
for(i=0;i<10;i++){
p1[i]=new pressure();
p1[i].start();
}
// すべてのスレッドが終了するのを待つ
try{
for(i=0;i<10;i++) p1[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 というキーワードを用
意してある.この使い方は,メソッドにつける.ブロックにつけるなどいろい
ろある.先ほどの例では,
// pressure1を Threadのサブクラスとして定義
// Threadによって動く実体とする
class pressure1 extends Thread{
// 圧力が安全圏内なら加える
static synchronized void RaisePressure(){
// 現在の圧力が制限値よりも15を超して少ないなら
int pval=p1.pressureGauge;
if(pval < p1.safetyLimit-15){
// わざと 100ms(0.1秒)待つ
try{sleep(100);} catch(Exception e){}
// 圧力を15加える
p1.pressureGauge+=15;
System.out.println("pval="+pval+", p1.pressureGauge="+p1.pressureGauge);
}
else{
System.out.println("Failed adding pressure");
}
}
// pressureのインスタンスに対して startするとここが呼ばれる.
public void run(){
RaisePressure();
}
}
public class p1 {
// p1クラスの静的変数なのでプログラム全体から共有される
// 圧力値
static int pressureGauge=0;
// 圧力の制限値
static final int safetyLimit=20;
public static void main(String[] args){
pressure1 [] p1=new pressure1[10];
int i;
// 10個の Threadを作り,次々と作成
for(i=0;i<10;i++){
p1[i]=new pressure1();
p1[i].start();
}
// すべてのスレッドが終了するのを待つ
try{
for(i=0;i<10;i++) p1[i].join();
}
catch (Exception e){}
System.out.println("gauge reads "+pressureGauge+", safe limit is 20");
}
}
のようにRaisePressureにsynchronized というキーワードを付けると,同じク
ラスのオブジェクトが,RaisePressureを同時に実行するのを防ぐことができ
る.
メソッドRaisePressureが static になっていないと,synchronizedにより,
「同時には実行しない」単位が,「同じインスタンスに対するメソッド
RaisePressureの呼び出し」というものになるので,このケースではふさわしくない.
|
アニメーション