- PR -

java.util.concurrent.atomicパッケージに関しての質問

1
投稿者投稿内容
未記入
会議室デビュー日: 2006/10/15
投稿数: 2
投稿日時: 2006-10-15 23:10
javaのconncurrentパッケージを使えば、スレッド間で
共有リソースにアクセスするような処理において、Synchoronaized同期
を取らなくともデータの整合性を保つことができる。とのことなのですが、
DBを使ったシステムにおいても、このConcurrentパッケージを使えば
Synchoronized同期を使わなくともDBのデータの整合性が取れるのでしょうか。

ウィキペディアより引用**************************

銀行口座への預金プログラムを作るとする。それぞれのスレッドをATMとする。
預金預け入れをするには、現在の預金残高を読み出し、預入金額を足し算し、
新しい預金残高を書き込むという処理が必要である。ロック方式のやり方の場
合、1つ目のATMが預金をするために、口座にロックをかけ、2つ目のATMが同時
に預金残高を変更できないようにロックをかける。さもないと、同時に処理し
てしまうと、最終的な預金残高に不整合が起きうる。この処理を Lock-free に
するには、すべての預入要求を管理するスレッドを作り、そこに、Wait-free の
キューを作り、ATMはそのキューに対して非同期にロックをかけることなく預入要
求を入れ、預入要求を管理するスレッドはキューから順次取り出し、預金残高を更
新する。このやり方の方が、わざわざ Lock-free の預金アルゴリズムを作るよりも
、プログラミングは楽である。さらに、この手法は、キューがWait-freeであるので、
Lock-free なだけでなく、Wait-freeでもある。預金残高の書き換え処理をn並列で行
いたいなら、n個Wait-freeキューを作り、口座番号をnで割った余りでどのキューに
入れるか決めるという方法で対応できる。

***************************************

このようにウィキペディアには書かれているのですが、ほんとうにこのような処理で
Lockを掛けずとも、DBのデータの整合性は保てるのでしょうか?

例えばATMから預入管理スレッドのキューに対し、非同期に預け入れ要求を格納すると
なっていますが、ある口座に関しての預け入れ要求をキューに格納し、その要求を元にDBの更新処理を実行するまでの間に、他のスレッドから同じ口座に関しての預け入れ要
求をキューの中に格納してしまった場合、一気にDBのデータの整合性が崩れそうな気が
するのですが・・・
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-10-16 02:55
引用:

未記入さんの書き込み (2006-10-15 23:10) より:
javaのconncurrentパッケージを使えば、スレッド間で
共有リソースにアクセスするような処理において、Synchoronaized同期
を取らなくともデータの整合性を保つことができる。とのことなのですが、
DBを使ったシステムにおいても、このConcurrentパッケージを使えば
Synchoronized同期を使わなくともDBのデータの整合性が取れるのでしょうか。



synchoronizedを使わないでも可能か、という点には、
synchoronizedを使えば可能な事はjava.util.concurrentを使っても可能です。

入り口となる箇所をConcurrentなQueueを使ったConsumer/Producerを正しく、
かつ他にDB更新を行うスレッド/プロセス/ノードがない状態で行えば整合性を
保てるでしょうし、そうでないならば整合性は保てません。

java.util.concurrentパッケージを使ってできることは、synchronized/wait/notifyを
使って実現出来ることとそこまで大きな違いはなく、Lock-freeな手法を使えたり、
Java標準のプリミティブな同期機構よりも高水準なサービスを利用できたり、
競合時のスループット低下が少なかったりするといった付加的なものです。

引用:

例えばATMから預入管理スレッドのキューに対し、非同期に預け入れ要求を格納すると
なっていますが、ある口座に関しての預け入れ要求をキューに格納し、その要求を元にDBの更新処理を実行するまでの間に、他のスレッドから同じ口座に関しての預け入れ要
求をキューの中に格納してしまった場合、一気にDBのデータの整合性が崩れそうな気が
するのですが・・・



他のスレッドに同じ口座の預け入れ要求がキューイングされた時点で、

引用:

預金残高の書き換え処理をn並列で行いたいなら、n個Wait-freeキューを作り、
口座番号をnで割った余りでどのキューに入れるか決めるという方法で対応できる。



n並列を行う際の前提が覆されていませんか?

java.util.concurrentを使うことで何かを実現できるのではなく、
実現が容易になったり、きめ細かな制御を行うことが出来るだけです。

他の環境と較べて桁違いに高度なサービスである事も事実なわけですが。
未記入
会議室デビュー日: 2006/10/15
投稿数: 2
投稿日時: 2006-10-17 20:10
あしゅさんご返答ありがとうございます。

引用:-------------------------------------------------------------------------

    入り口となる箇所をConcurrentなQueueを使ったConsumer/Producerを正しく、
    かつ他にDB更新を行うスレッド/プロセス/ノードがない状態で行えば整合性を
    保てるでしょうし、そうでないならば整合性は保てません。

-------------------------------------------------------------------------------

これはATMから預入管理スレッドのキューに対し、預け入れ要求を入れて、その要求をキューから取り出し実行してから、次の要求をキューの中に入れるということでしょうか?

@現在の預金残高を読み出す
A預入金額を足し算する
B新しい預金残高を書き込む

の3ステップの内@、Aの処理が終了すると各スレッドは預け入れ管理スレッドのキューに対し、Lock-freeに預け入れ要求を格納していき、
預け入れ管理スレッドは、キューから要求を取り出し逐次的にDBを更新する。
といったイメージで考えていたのですが、これではキューに溜まったDB更新要求を
実行する前に、キューに格納されているデータ更新予定口座と同じ口座が異なるATM
から預け入れ要求を出したときに、まだDBが更新される前のデータを基に預け入れ
要求を作ってしまうので、データの整合性が取れなくなってしまうと思ったのですが
これは、どうにかして解決できることなのでしょうか?

SynchoronaizedでLockをかけて実現できる事をConcurrentパッケージを使いLock-freeに実現できるならば、是非試してみたいと考えているのですが。

未記入
ぬし
会議室デビュー日: 2004/09/17
投稿数: 667
投稿日時: 2006-10-17 23:26
引用:

@現在の預金残高を読み出す
A預入金額を足し算する
B新しい預金残高を書き込む

の3ステップの内@、Aの処理が終了すると各スレッドは預け入れ管理スレッドのキューに対し、Lock-freeに預け入れ要求を格納していき、預け入れ管理スレッドは、キューから要求を取り出し逐次的にDBを更新する。


違うよ。預け入れ管理スレッドが@〜Bまでをすべてやるんだよ。ほかのスレッドは「A口座に100円足しとけよ」とか「B口座に 200円足しとけよ」とかキューに突っ込むだけ。ノンブロッキングで、各スレッドが預金残高の読み取りや加算後残高の計算をすることなんてできない。

concurrent は魔法のパッケージじゃないんで常識で考えましょう。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-10-18 02:48
引用:

未記入さんの書き込み (2006-10-17 20:10) より:
SynchoronaizedでLockをかけて実現できる事をConcurrentパッケージを使いLock-freeに実現できるならば、是非試してみたいと考えているのですが。



試すことは良いことだと思います。
ただし、concurrentパッケージのlockやatomicは、

「DBMSを実装しようとする人」にとっては涎が出そうな代物ですが、
「DBMSを利用したプログラムを実装しようとしている人」にとっては、
さほど大きな意味は持たない物だと言うことを憶えておきましょう。

dW : Java technology : Javaの理論と実践: JDK 5.0における、より柔軟でスケーラブルなロック
dW : Java technology : Javaの理論と実践: アトミックで行く
1

スキルアップ/キャリアアップ(JOB@IT)