<目次>
(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)