<目次>
(1) Javaのsynchronizedとは?ある場合とない場合のサンプルPGを比較付き
(1-1) synchronizedの概要
(1-2) synchronizedの構文
(1-3) synchronizedが無い場合(非同期)の例
●main文(スレッド生成・実行)
●各スレッドの中で実行する処理
●同期対象のオブジェクト
(1-4) synchronizedがある場合(同期)の例①【メソッドをsynchronized】
(1-5) synchronizedがある場合(同期)の例②【オブジェクトをsynchronized】
(1) Javaのsynchronizedとは?ある場合とない場合のサンプルPGを比較付き
(1-1) synchronizedの概要
マルチスレッドの処理において、複数スレッドが同時に同じ共有データを更新しようとした場合に「競合状態」が発生する可能性があります。Javaではそれを防ぐための「同期」機能(synchronizedキーワード)があります。
synchronizedを使ったブロックは、データに同時にアクセスする「スレッド」を1つに限定する事ができ、これにより「競合状態」を防ぐ事ができます。
(1-2) synchronizedの構文
「synchronized」キーワードの( )の中に同期対象のリソース、つまりロックを掛けて1スレッドのみが使える対象のオブジェクト(変数でもオブジェクトでも)を指定します。{ }の中で、オブジェクトのロックを取得した際に実行する処理を指定します。
synchronized([同期対象のリソース])
{
//# 共有アクセスにリソースして処理を行う
}
これにより、synchronizedの箇所に到達すると、スレッドが対象リソース(オブジェクトや変数など)を自動でロックし、他のスレッドがアクセスできないように制御します。そしてスレッドの処理が完了すると、ロックを解放します。
(1-3) synchronizedが無い場合(非同期)の例
「同期」(synchronized)のサンプルプログラムを見る前に、「synchronized」を使わない場合(非同期)に起きる弊害の例をご紹介します。
●main文(スレッド生成・実行)
スレッド1(st1)とスレッド2(st2)を生成・処理実行するmain文です。SyncCalc型の「scobj」は同期対象のオブジェクト(1度に1スレッドのみロックを許可する)対象です。
//# 【クラス】2つのスレッドで処理を流すmain文
//# (synchronized確認用)
public class SynchronizedSample {
//# main文
public static void main(String args[]) {
//# 同期対象のリソース
//#(1度に1スレッドのみ専有可能)
SyncCalc scobj = new SyncCalc();
//# 各スレッドのインスタンス生成
SyncTask st1 = new SyncTask(scobj, 2);
SyncTask st2 = new SyncTask(scobj, 3);
//# 各スレッドの処理実行
st1.start();
st2.start();
}
}
●各スレッドの中で実行する処理
各スレッドにて、累乗計算を起動するスレッド(Threadを継承)のクラスです。
//# 【クラス】各スレッドの中で実行する処理
public class SyncTask extends Thread {
//# メンバ変数
private SyncCalc sc;
private int calctarget;
//# コンストラクタ
SyncTask(SyncCalc sc,int calctarget){
this.sc = sc;
this.calctarget = calctarget;
}
//# スレッドに必要なrunメソッドのオーバーライド
public void run() {
//# 累乗の計算を実行
sc.calculate(calctarget);
}
}
●同期対象のオブジェクト
ロック対象の「SyncCalc」クラスです(ただの累乗計算)。
//# 【クラス】同期対象のオブジェクト(各スレッドのロック対象)
public class SyncCalc {
void calculate(int num) {
//引数の1乗~5乗を計算
for(int i=1; i<=5; i++) {
System.out.println(num+" の "+i
+" 乗 = "+(int)Math.pow(num,i));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

(1-4) synchronizedがある場合(同期)の例①【メソッドをsynchronized】
次に上記の非同期のサンプルに「synchronized」キーワードを追加して同期処理にした例①をご紹介します。この例では「メソッド」に対してsynchronizedを付与する事で同期しています。
//# 【クラス】同期対象のオブジェクト(各スレッドのロック対象)
public class SyncCalc {
void calculate(int num) {
(変更後)
//# 【クラス】同期対象のオブジェクト(各スレッドのロック対象)
public class SyncCalc {
synchronized void calculate(int num) {

(1-5) synchronizedがある場合(同期)の例②【オブジェクトをsynchronized】
次に上記の非同期のサンプルに「synchronized」キーワードを追加して同期処理にした例②をご紹介します。この例では「オブジェクト」に対してsynchronizedを付与する事で同期しています。
//# スレッドに必要なrunメソッドのオーバーライド
public void run() {
//# 累乗の計算を実行
sc.calculate(calctarget);
}
(変更後)
//# スレッドに必要なrunメソッドのオーバーライド
public void run() {
//# 累乗の計算を実行
synchronized(sc){
sc.calculate(calctarget);
}
}
(図142)
