2017-08-09 15 views
-1

私は、複数のスレッドからアクセスされるオブジェクトを持っています。私はそれを実装したいので、セッターとゲッターにアクセスするには、呼び出し元は先に明示的にロックしてから終了しなければなりません。私は同期メソッドを使用していますが、それはjavaのより明示的なロックAPIに比べて非常に単純なようには見えません。これはReentrantLockを使用した私の現在のスタブ付き実装です。Javaオブジェクトのロックを明示的に保持する方法

public class Data { 
    private ReentrantLock lock; 

    private int IntValue; 

    public Data() { 
     this.IntValue = 0; 
     this.lock = new ReentrantLock(); 
    } 


    public void Lock() { 
     lock.lock(); 
    } 

    public void Unlock() { 
     if (!lock.isLocked()) { 
      return; 
     } 
     //only the thread owning the lock can proceed to unlock 
     lock.lock(); 
     int lockCount = lock.getHoldCount(); 
     for (int i = 0; i < lockCount; i++) { 
      lock.unlock(); 
     } 
    } 

    public void SetVal(int val) { 
     if (!lock.isLocked()) { 
      return; 
     } 
     lock.lock(); 
     this.IntValue = val; 
    } 
} 

スレッドがSetVal(int val)を呼び出したい場合は、まずLock()を呼び出してからUnlock()を呼び出す必要があります。私はsetter/getterメソッドでisLocked()チェックを配置してこのルールを適用しました。そして、ロックを所有しているスレッドだけがロック解除(ReentrackLockのユニークな機能)に進むことができるように、ロック解除で追加のロック呼び出しを追加しました。オブジェクトのセッター/ゲッターはUnlock()メソッドが呼び出される前に何度も呼び出すことができます。ですから、Unlock()メソッドでは、HoldCountを繰り返し実行し、各カウントごとにロックを解除する必要があります。

これを達成するための効率的かつ慣用的な方法があるのだろうかと思いますが?

+2

え:

これはOOPのパラダイムについて適切にそれを行うだろうかありますか?メソッドを同期させるだけです。発信者側では何もしなくてもかまいません。もっと簡単なことはありません。 – EJP

+0

メソッド呼び出しごとにオブジェクトのロックが失われませんか?私はそれを望んでいない。私はスレッドがメソッド呼び出しのシーケンス中にオブジェクトにロックを持つことを保証したいと思います。 –

+0

ああ、私はちょうど同期(データ)ブロックを行い、ブロック内のデータのメソッドへの呼び出しをすると、そのトリックを行うだろうか? –

答えて

0

だけint型の値を使用している場合は、AtomicInteger

のために行くか、競合状態からないようにすることを、すべてのメソッドを同期することができます。

または同期と標準の両方をサポートしたい場合は、collections.SynchronizedSetのようなラッパーをピットすることができます。これが役に立ちます。

0

あなたのアプローチでは間違った方向に走っています。 OOPのパラダイムでは、すべてのデータを内部的に保管し、管理する必要がありますが、内部データを呼び出し側に渡すことでそのコントロールを外部化することです。

良い設計は、ロックが必要であるという事実を隠そうとし、そのようなタスクから発信者を解放するために内部的に行います。特に、適切なロックの責任を呼び出し元に転送すると、すべての単一の呼び出し元が潜在的なスレッドの問題になる可能性があるためです。しかし、内部的にロックすると、潜在的なバグのソースは1つしかないので、問題が発生した場合は、どこを見ているか分かります。

public class Data { 
    // protected so it is accessible to derived classes 
    // final so the lock object cannot be (accidentally) reassigned 
    // Lock (base class) so it is easier to change the implementation later 
    protected final Lock lock; 

    // clear naming 
    private int value; 

    public Data() { 
     // value is automatically initialized with 0 
     this.lock = new ReentrantLock(); 
    } 

    // by convention the setter for ... is set... 
    public void setValue(final int value) { 
     this.lock.lock(); 
     // absolutely use try/finally here, to ensure it is unlocked in all cases 
     try { 
      this.value = value; 
     } finally { 
      this.lock.unlock(); 
     } 
    } 

    // by convention the getter for ... is get... 
    public int getValue() { 
     this.lock.lock(); 
     try { 
      return this.value; 
     } finally { 
      this.lock.unlock(); 
     } 
    } 
} 
関連する問題