「ダブル・チェック・ロッキング」の版間の差分
imported>GamerBook (→Java) |
|||
1行目: | 1行目: | ||
− | '''ダブル・チェック・ロッキング''' | + | '''ダブル・チェック・ロッキング'''([[英語]]:Double Check Locking)とは、マルチスレッド環境下における[[変数]]に対して、初回は[[ロック]]せず状態チェックを行い、そこで必要であれば再度[[ロック]]を掛けたのちに状態チェックを行うという[[ソフトウェア]]の[[最適化]]技法、[[デザインパターン]]のひとつである。 |
− | [[ロック]]は非常に[[オーバーヘッド]] | + | [[変数]]の[[ロック]]は非常に[[オーバーヘッド]]の大きい重たい処理であるため、その発生回数を可能な限り減らすことで[[プログラム]]の高速化を実現しようというものである。 |
ダブル・チェック・ロッキングは、主に[[マルチスレッド]]環境下での[[シングルトンパターン]]を実装する際に[[オーバーヘッド]]の低減を目的として使われることが多い。 | ダブル・チェック・ロッキングは、主に[[マルチスレッド]]環境下での[[シングルトンパターン]]を実装する際に[[オーバーヘッド]]の低減を目的として使われることが多い。 | ||
76行目: | 76行目: | ||
=== Java === | === Java === | ||
− | [[Java]] | + | [[Java]]では[[仕様]]において[[アウトオブオーダー]]を用いるメモリモデルが可能となっていたため、この[[イディオム]]を使うことには問題があり、一部の[[実装]]では実際に正しく働かない可能性があることが知られている。詳細は http://www.ibm.com/developerworks/jp/java/library/j-dcl/ を参照。 |
− | |||
[[Java]]では絶対にダブルチェックロッキングを使用してはならない。 | [[Java]]では絶対にダブルチェックロッキングを使用してはならない。 | ||
− | |||
たとえば以下のような[[Java]]の[[ソースコード]]があったとする。 | たとえば以下のような[[Java]]の[[ソースコード]]があったとする。 | ||
123行目: | 121行目: | ||
== 参考文献 == | == 参考文献 == | ||
{{reflist}} | {{reflist}} | ||
− | |||
− | |||
− | |||
{{stub}} | {{stub}} |
2014年10月26日 (日) 01:29時点における版
ダブル・チェック・ロッキング(英語:Double Check Locking)とは、マルチスレッド環境下における変数に対して、初回はロックせず状態チェックを行い、そこで必要であれば再度ロックを掛けたのちに状態チェックを行うというソフトウェアの最適化技法、デザインパターンのひとつである。
変数のロックは非常にオーバーヘッドの大きい重たい処理であるため、その発生回数を可能な限り減らすことでプログラムの高速化を実現しようというものである。
ダブル・チェック・ロッキングは、主にマルチスレッド環境下でのシングルトンパターンを実装する際にオーバーヘッドの低減を目的として使われることが多い。
主なプログラミング言語での実装例
C#
C#における標準的なダブル・チェック・ロッキングの実装方法を示す。この記述方法ではC#のキーワードのひとつであるvolatileを用いているのがミソである。なおvolatileキーワードと同等の機能を提供していない.NET Framework系のプログラミング言語も多く、それらでは別の実装方法を検討する必要がある。
public class MySingleton
{
private static object _sync = new object();
private static volatile MySingleton _instance = null;
// プライベートコンストラクター
// ※本クラスを除き、newキーワードによるインスタンス生成を出来なくする。
private MySingleton()
{
}
//
public static MySingleton GetInstance()
{
// 1回目のチェック
// ロックしていないので高速に処理される
if (null == _instance)
{
// ロック
// ※このブロック内はクソ重い
lock (_sync)
{
// 2回目のチェック
if (null == _instance)
{
_instance = new MySingleton();
}
}
}
return _instance;
}
}
C# (Lazy)
.NET Framework 4.0では、標準でLazy<T>クラスが用意されており、それを使うことでよりシンプルにダブル・チェック・ロッキングを記述できるようになった。 この記述方法はC#に依存した機能も特に使われておらず、.NET Framework系の様々なプログラミング言語へも特に悩むことなく移植・実装可能であると思われる。
using System;
public class MySingleton
{
private static readonly Lazy<MySingleton> _instance
= new Lazy<MySingleton>(() => new MySingleton());
private MySingleton()
{
}
public static MySingleton GetInstance()
{
return _instance.Value;
}
}
Java
Javaでは仕様においてアウトオブオーダーを用いるメモリモデルが可能となっていたため、このイディオムを使うことには問題があり、一部の実装では実際に正しく働かない可能性があることが知られている。詳細は http://www.ibm.com/developerworks/jp/java/library/j-dcl/ を参照。
Javaでは絶対にダブルチェックロッキングを使用してはならない。
Person hage = new Person();
これが一部のJava実装では以下のような動作になる。
public static Singleton getInstance()
{
// 1: 先行スレッドから見た場合はnull
//
// 3: 後続スレッドから見た場合は非null、
// ただしコンストラクタが実行されていない不完全なものである場合がある。
if (instance == null)
{
synchronized(Singleton.class)
{
if (instance == null)
{
// 2:
// 先行スレッドによりメモリが割り当てられてnullではなくなるが、
// この時点でコンストラクタは実行されていない。
instance = new Singleton();
}
}
}
return instance;
}