10.3.2. LockManager

同時実行制御はLockManagerクラスにより実装され、適切なデフォルト動作を提供しますが、必要であればこの動作をオーバーライドすることもできます。setlockメソッドは、同時実行制御に対する主なインターフェースとなっています。デフォルトでは、JBoss Transaction Service のランタイムシステムは、オブジェクト毎にmultiple reader, single writerポリシーに従うといった厳密な2相ロッキングを強制します。LockManager クラスは操作が読み込みロックあるいは書き込みロックのいずれが必要なのか推測できないため、プログラマがロック取得を制御します。しかし、ロック解除は通常システムが制御しており、プログラマは何もする必要がありません。
LockManager クラスは、オブジェクトへのロック設定あるいはロック解除に関するリクエストを管理します。しかし、StateManagerから取得しているため、継承した機能の一部に関する呼出しも制御することができます。例えば、書き込みロックを設定するリクエストが許可された場合、書き込みロックを設定するということは、呼出中のメソッドがオブジェクトの変更を行うであろうと推測できるため、LockManager は、modified メソッドを直接呼び出します。オブジェクトが回復可能であれば、こうすることでリカバリ情報が保存されます。ロックを問題なく取得すると、activateの呼出しがトリガーされます。
そのため、LockManager は永続オブジェクトのアクティベートおよび解除を行い、同時実行制御の管理に利用するResources を登録します。また、StateManager クラスを駆動することで、永続および回復可能なステートを操作し、オブジェクトのリカバリを行えるようにResources を登録します。自身で行う操作は、適切なロックを設定し、トランザクションを開始・終了し、StateManager クラスのsave_staterestore_stateメソッドを継承するのみです。

例10.9 LockResult の例

public class LockResult
{
    public static final int GRANTED;
    public static final int REFUSED;
    public static final int RELEASED;
};

public class ConflictType
{
    public static final int CONFLICT;
    public static final int COMPATIBLE;
    public static final int PRESENT;
};

public abstract class LockManager extends StateManager
{
    public static final int defaultTimeout;
    public static final int defaultRetry;
    public static final int waitTotalTimeout;

    public synchronized int setlock (Lock l);
    public synchronized int setlock (Lock l, int retry);
    public synchronized int setlock (Lock l, int retry, int sleepTime);
    public synchronized boolean releaselock (Uid uid);

    /* abstract methods inherited from StateManager */

    public boolean restore_state (InputObjectState os, int ObjectType);
    public boolean save_state (OutputObjectState os, int ObjectType);
    public String type ();

    protected LockManager ();
    protected LockManager (int ObjectType, ObjectName attr);
    protected LockManager (Uid storeUid);
    protected LockManager (Uid storeUid, int ObjectType, ObjectName attr);
    . . .
};
必要なロックタイプと再試行の回数をパラメータとしてsetlock に渡し、ロックを取得する必要があります。タイプは、READ あるいは WRITEになっています。ロックの矛盾が起こると、以下のシナリオの1つのようになります。
  • 再試行の値がREAD or WRITEと同じ場合、setlock メソッドを呼び出したスレッドはロックが解除されるか、指定した合計タイムアウトを過ぎるまでブロックされます。タイムアウトになると、REFUSED の値が返されます。
  • ロックを最初に取得できない場合、LockManager が指定された回数を再試行し、試行に失敗してから次に失敗するまで指定のタイムアウト値の期間待機します。デフォルトの試行回数は100で、各試行の間隔は0.25秒となっています。
ロックに矛盾が発生すると、ロックのリクエストはタイムアウトしデッドロックが起こらないようにします。完全なデッドロック検出スキームが提供されています。リクエストされたロックを取得した場合、setlock メソッドは、GRANTEDの値を返しますが、取得しなかった場合はREFUSEDの値を返します。ロックリクエストが許可された場合にのみ、操作に対するコードの残りが実行されるようにする必要があります。実用例については、例10.10「setlock の例」を参照してください。

例10.10 setlock の例

res = setlock(new Lock(WRITE), 10); 
// Attempts to set a write
// lock 11 times (10 retries)
// before giving up.
      
res = setlock(new Lock(READ), 0); 
// Attempts to set a read lock
// 1 time (no retries) before
// giving up.
      
res = setlock(new Lock(WRITE); 
// Attempts to set a write lock
// 101 times (default of 100
// retries) before giving up.
同時実行制御のメカニズムをアトミックアクションのメカニズムへ統合することで、オブジェクトへのロックが許可され、適切な情報が現在動作中のアトミックアクションに登録されるようにします。こうすることで、ロックを正しいタイミングで解除し、アトミックアクション内で取得したロックを明示的に解除する必要性をなくします。ただし、アトミックアクションの範囲外でオブジェクトへのロックを取得した場合、 releaselockメソッドを使いロックを解除する必要があります。