jp.terasoluna.fw.web.thin
クラス LimitedLock

java.lang.Object
  上位を拡張 java.util.concurrent.locks.ReentrantLock
      上位を拡張 jp.terasoluna.fw.web.thin.LimitedLock
すべての実装されたインタフェース:
Serializable, Lock

public class LimitedLock
extends ReentrantLock

ロック待ちスレッドが増えた際に、古いロック待ちスレッドを中断する機能を持つロッククラス。

Webにおいて、セッションで同期化する場合、synchronizedによる同期化実装では、 以下のような操作を行うユーザがいた場合に、 スレッドを無駄に占有してしまう(大量のスレッドがロック待ち状態になってしまう)問題がある。

  1. 極端にレスポンスの悪い処理を実行する
  2. なかなかレスポンスが返ってこないので、操作をやり直すため、お気に入り等からトップページに移動する
    (セッションで同期化しているので、1の処理が終わるまでは表示されない)
  3. トップページがなかなか表示されないため、リロードを繰り返す。

このような操作が行われた場合、2で発生したリクエストを処理中のロック待ちスレッドや、 3で繰り返しているリクエストのうち、最後のリクエスト以外を処理中のロック待ちスレッドは、 処理を続けても、レスポンスがクライアントの画面には反映されないため、ロック待ち自体を中断した方がよい。
この中断機能を実装したのが、このクラスである。

このクラス内部の基本的なルールは以下の通りである。

(クラス外部から割り込みステータスが設定された場合は例外。例えば、既に割り込みステータスを設定されているスレッドがロック待ちしようとした場合、スーパークラスの機能により、ロック待ちせずに中断される。)

このクラス内部の基本的な動作は以下の通りである。

例) しきい値が2のとき
スレッド1, 2, 3, 4の順でロックを要求した場合、 スレッド1がロックを取得し、スレッド2, 3, 4がロック待ちとなる。
このとき、ロック待ちスレッド(3)がしきい値(2)を超えているので、 さらにスレッド5がロックを要求したとき、 もっとも古いロック待ちスレッドである、スレッド2のロック待ちを中断し、 スレッド5がロック待ち状態となる。

ロックを取得したスレッドがロックを返すまでの間、 別のスレッドが順次、次々とロックを要求した場合(並行して要求しない場合)、 ロック待ちスレッド数は、しきい値と、しきい値+1の間を遷移する。
また、新たなロック要求がない期間においては、ロック待ちスレッド数は、しきい値+1となる。
ただし、並行して要求があった場合の、ロック待ちスレッド数の上限は保証しない。
また、外部で同期化してはならない。
(同期化すると、多数のスレッドをロック待ちにしてしまう事象を回避するという、このクラスの目的が果たせない。)
よって、ロック待ちスレッド数の上限は、ベストエフォートとなる。

このクラスでは、lockInterruptiblyメソッドでロックを取得し、 unlockメソッドでロックを解放する。
その他のロック制御メソッド(スーパークラスで用意されているメソッド)は使用しないこと。

ロック待ちが中断されたスレッドは、 lockInterruptiblyメソッドを実行中に、InterruptedExceptionが発生することにより、 ロック待ち状態から復帰する。

このクラスの中断(スレッド割り込み)機構により、InterruptedExceptionが発生した場合、 スレッドの割り込みステータスはクリアされる。
ただし、このクラスの外部からのスレッド割り込みがある場合には、このクラスの処理を抜けた際の スレッドの割り込みステータスは不定である。
外部割り込みのタイミングによっては、 InterruptedExceptionが発生しつつ、割り込みステータスも設定されている状態となることがある。 (InterruptedException発生後、割り込みステータスクリアコードが実行された後に、外部割り込みが発生した場合が該当。)

コード記述例:

 LimitedLock lock;
 … 同期化したい範囲で共有するLimitedLockインスタンスを取得
 try {
     lock.lockInterruptibly();
     … ロック取得後の処理
 } catch (InterruptedException e) {
     … ロック待ち中断時の処理
 } finally {
     lock.unlock(); // ロックの取得に成功したか失敗したかの事前判定は不要。(内部で自動判定)
 }
 

このクラスは、スーパークラスでSerializableが実装されているため、直列化可能な実装としているが、使い方次第では、このクラスの目的を果たすことが出来なくなる可能性が高いため、シリアライズ/デシリアライズの使用は推奨しない。 (セッションに格納することも推奨しない。) なお、デシリアライズ時は、スーパークラスと同様、シリアライズされたときの状態に関わらず、ロックが解除された状態となる。

関連項目:
ReentrantLock, 直列化された形式

コンストラクタの概要
LimitedLock(int threshold)
          コンストラクタ。
 
メソッドの概要
 void lockInterruptibly()
          ロックを取得する。
 void unlock()
          ロックを解放する。
 
クラス java.util.concurrent.locks.ReentrantLock から継承されたメソッド
getHoldCount, getOwner, getQueuedThreads, getQueueLength, getWaitingThreads, getWaitQueueLength, hasQueuedThread, hasQueuedThreads, hasWaiters, isFair, isHeldByCurrentThread, isLocked, lock, newCondition, toString, tryLock, tryLock
 
クラス java.lang.Object から継承されたメソッド
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

コンストラクタの詳細

LimitedLock

public LimitedLock(int threshold)
コンストラクタ。

パラメータ:
threshold - しきい値(0以下の場合は、0として扱う)
メソッドの詳細

lockInterruptibly

public void lockInterruptibly()
                       throws InterruptedException
ロックを取得する。

現在のスレッドがロックが取得できるか、他のスレッドが現在のスレッドに割り込みを行うまで、現在のスレッドは待機する。
現在のスレッドがロックが取得できた場合、メソッドを復帰する。
他のスレッドが現在のスレッドに割り込みを行った場合、InterruptedExceptionがスローされ、現在のスレッドの割り込みステータスがクリアされる。
(ただし、クラス外部からの割り込みがあった場合は、割り込みステータスは不定。)

上記は、スーパークラスによるもの。拡張ポイントは以下の通り。

定義:
インタフェース Lock 内の lockInterruptibly
オーバーライド:
クラス ReentrantLock 内の lockInterruptibly
例外:
InterruptedException - 現在のスレッドで割り込みが発生した場合(このクラスの機能により、ロック待ちが中断された場合を含む)
関連項目:
ReentrantLock.lockInterruptibly()

unlock

public void unlock()
ロックを解放する。

現在のスレッドがこのロックのホルダである場合、スーパークラスのメソッドにより、ロックを解放する。

このクラスでの拡張ポイントは以下の通り。
・このロックのホルダでないスレッドがこのメソッドを実行しても、例外をスローしない。(何もせずに復帰する)

定義:
インタフェース Lock 内の unlock
オーバーライド:
クラス ReentrantLock 内の unlock
関連項目:
ReentrantLock.unlock()


Copyright © 2012. All Rights Reserved.