「ダブル・チェック・ロッキング」を編集中
ナビゲーションに移動
検索に移動
この編集を取り消せます。 下記の差分を確認して、本当に取り消していいか検証してください。よろしければ変更を保存して取り消しを完了してください。
最新版 | 編集中の文章 | ||
1行目: | 1行目: | ||
− | '''ダブル・チェック・ロッキング'''([[英語]]:double check locking)とは、[[マルチスレッド]]環境下における[[変数]]に対して、初回は[[ロック]] | + | '''ダブル・チェック・ロッキング'''([[英語]]:double check locking)とは、[[マルチスレッド]]環境下における[[変数]]に対して、初回は[[ロック]]せず状態チェックを行い、そこで必要であれば再度[[ロック]]を掛けた後に状態チェックを行うという[[ソフトウェア]]の[[最適化]]技法、[[デザインパターン]]のひとつである。 |
==概要== | ==概要== | ||
ダブル・チェック・ロッキングは、主に[[マルチスレッド]]環境下での[[シングルトンパターン]]を実装する際に[[オーバーヘッド]]の低減を目的として使われることが多い。 | ダブル・チェック・ロッキングは、主に[[マルチスレッド]]環境下での[[シングルトンパターン]]を実装する際に[[オーバーヘッド]]の低減を目的として使われることが多い。 | ||
− | マルチスレッド下における[[変数]]の[[ロック]]は非常に[[オーバーヘッド]]が大きくスレッド数に比例して重くなる。ダブル・チェック・ロッキングはそのような状況下でロックの発生回数を可能な限り減らすことで[[プログラム]] | + | マルチスレッド下における[[変数]]の[[ロック]]は非常に[[オーバーヘッド]]が大きくスレッド数に比例して重くなる。ダブル・チェック・ロッキングはそのような状況下でロックの発生回数を可能な限り減らすことで[[プログラム]]の高速化を実現しようというものである。なお、シビアな速度を要求されないのであれば[[ソースコード]]としては何も考えず常にロックした方が簡潔明瞭ではある。 |
− | |||
− | |||
== 主なプログラミング言語での実装例 == | == 主なプログラミング言語での実装例 == | ||
26行目: | 24行目: | ||
public static MySingleton GetInstance() | public static MySingleton GetInstance() | ||
{ | { | ||
− | // | + | // 1回目のチェック |
− | // | + | // ロックしていないので高速に処理される |
if (null == _instance) | if (null == _instance) | ||
{ | { | ||
// ロック | // ロック | ||
− | // | + | // ※このブロック内はクソ重い |
lock (_sync) | lock (_sync) | ||
{ | { | ||
− | // | + | // 2回目のチェック |
if (null == _instance) | if (null == _instance) | ||
{ | { | ||
79行目: | 77行目: | ||
=== Java === | === Java === | ||
− | [[Java]]では[[仕様]]において[[アウトオブオーダー]]を用いるメモリモデルが可能となっていたため、この[[イディオム]]を使うことには問題があり、一部の[[実装]]では実際に正しく働かない可能性があることが知られている。詳細は http://www.ibm.com/developerworks/jp/java/library/j-dcl/ | + | [[Java]]では[[仕様]]において[[アウトオブオーダー]]を用いるメモリモデルが可能となっていたため、この[[イディオム]]を使うことには問題があり、一部の[[実装]]では実際に正しく働かない可能性があることが知られている。詳細は http://www.ibm.com/developerworks/jp/java/library/j-dcl/ を参照。 |
− | + | [[Java]]では絶対にダブルチェックロッキングを使用してはならない。 | |
たとえば以下のような[[Java]]の[[ソースコード]]があったとする。 | たとえば以下のような[[Java]]の[[ソースコード]]があったとする。 | ||
91行目: | 89行目: | ||
# 1行目で[[メモリ]]が確保される。 | # 1行目で[[メモリ]]が確保される。 | ||
#: いわゆるmallocが実行されhage[[変数]]自体は[[null]]ではなくなる。 | #: いわゆるmallocが実行されhage[[変数]]自体は[[null]]ではなくなる。 | ||
− | #: ただし[[コンストラクタ]] | + | #: ただし[[コンストラクタ]]はまだ実行されない。 |
− | # | + | # 2行目の初めて使うときにコンストラクタが実行される。 |
#: [[コンストラクタ]]が実行されるタイミングは、オリジナル(newを実行した[[スレッド]]の持つ)インスタンスに対して外部から[[メンバー関数]]や[[メンバー変数]]に初回アクセスがあったときとなる。これを[[遅延初期化]](lazy initialization)という。これによりhage[[変数]]自体は[[null]]ではないので後続スレッドはコンストラクタを実行していない不完全な[[インスタンス]]の[[参照]]を取得できてしまう。 | #: [[コンストラクタ]]が実行されるタイミングは、オリジナル(newを実行した[[スレッド]]の持つ)インスタンスに対して外部から[[メンバー関数]]や[[メンバー変数]]に初回アクセスがあったときとなる。これを[[遅延初期化]](lazy initialization)という。これによりhage[[変数]]自体は[[null]]ではないので後続スレッドはコンストラクタを実行していない不完全な[[インスタンス]]の[[参照]]を取得できてしまう。 | ||