0

次の使用例があります: m1 と m2 の 2 つのメソッドを持つクラスがあります。通常、m1() は同期する必要はありませんが、誰かが m2() を呼び出した場合、m2() が実行されている限り、m1() を同期する必要があります。これを実現するために、次のコードを思いつきました。よろしいですか?それにコメントして、より良いオプションを提案しますか?

注: この状況は実用的ではないことを認識しています。たとえば、あるスレッドが m1 の途中にあり、他のスレッドが m2 を呼び出している場合、問題が発生するためです (誰かが対処方法を指摘してくれると助かります)。それ); それにもかかわらず、私はこれについて考えるのが面白いと感じました。

public class DynamicSync
{
    volatile MyLock lock;   
    private final MyLock DUMMY_LOCK = new DummyMyLock();
    private final MyLock SYNCHRONIZED_LOCK = new SynchronizedMyLock();

    public DynamicSync()
    {
        lock = DUMMY_LOCK;
    }

    public void dynamicallySynchronizedMethod() // this is method m1() in the question above
    {
        lock.lock();
        // some logic
        lock.unlock();
    }

    public void setLockAndExecuteLogic() // this is method m2() in the question above
    {       
        synchronized(SYNCHRONIZED_LOCK)
        {
            lock = SYNCHRONIZED_LOCK;       
            // some logic                               
        }
    }

    interface MyLock
    {
        void lock();
        void unlock();
    }

    class DummyMyLock implements MyLock
    {
        @Override
        public void lock() 
        {
        }

        @Override
        public void unlock() 
        {
        }       
    }

    class SynchronizedMyLock implements MyLock
    {
        @Override
        public synchronized void lock() 
        {
            // no op
        }

        @Override
        public void unlock() 
        {
            lock = DUMMY_LOCK;
        }       
    }
}

編集:実際の問題は次のとおりです。私はオブジェクトプールを設計しています。ここでは、いくつのオブジェクトが割り当てられ、どのオブジェクトが残っているかを知る必要があります。そのため、2 つのコレクションを維持することを考えていました。origSet はすべてのオブジェクトを含む HashSet であり、dynaSet は ConcurrentSkipListSet であり、そこからオブジェクトを取り出して元に戻します。origSet と dynaSet の違いを理解する必要がある場合瞬時に、差が計算されるまで dyanSet を「フリーズ」する必要があります。しかし、この違いを取得することは非常にまれな操作になるため、私の質問です。

4

3 に答える 3

4

Java にはマルチスレッド同期用の広範な API があるため、競合状態の地獄で苦しんで死にたくない場合は、そのようなものを作成しようとしないことを強くお勧めします。

http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetzという本をすでに読んでいる場合は、次のことを行う必要があります。

  • 最善の解決策は、不変のままにして、スレッド同期の問題を世界から排除することです。
  • 不変を維持できない場合は、防御を維持し、共有するときに内部プロパティの防御コピーを作成します。これを「安全な公開」と呼びます
  • 不変を維持できない場合は、少なくとも並行コレクションを使用して、作業を楽にしてください。
  • 独自のロック システムを開発する必要がある場合は、Java ReadWriteLock を参照してください。

あなたの最後のコメントによると、私は 2 つの提案があります。

  1. コレクションのサイズを取得する必要があるだけで、データを使用してコレクションに対して何もしない場合。同期する必要はまったくないと思います。getDynaSize を呼び出すと、使用可能な最後の値が返されます。使用するときにそれが現在の値かどうかはわかりませんが、処理メソッド内で明らかに競合状態が見られない限り、まったく同期しないでください。(詳細を教えていただけないでしょうか?)

  2. 本当にロックする必要がある場合は、ReadWriteLock を使用してください。

    • これは再入可能なロックであるため、スレッドが既に取得されている場合、結果として得られる取得の試行はブロックされず、複数のリーダーが入ることができますが、ライターは 1 つだけです。
    • 並行コレクションに要素を追加する必要があるたびにライターを取得し、追加後に解放する必要があります。また、サイズを取得する前にライターロックを取得し、処理が完了したら解放する必要があります。
于 2012-07-19T08:04:38.310 に答える
3

安全に、両方を同期させてください。思いついたもの、またはここで提案されているものに対して、同時の正確性の証明を思いつくことができない限り、リスクは価値がありません。

編集:撤回します。そう言っている他の回答を読む前でさえ、これはむしろ共有読み取りロックのようなものであることに最終的に気づきました;-)m1()共有読み取りロックをm2()主張し、書き込みロックを主張します。次に、任意の数を同時に実行できますが、 &をm1()s同時に実行することはできず、2 つ同時に実行することはできません。m1()m2()m2()s

于 2012-07-19T07:58:11.267 に答える
2

これには a を使用することをお勧めしReadWriteLockます。とで保護m1()します。readLock()m2()writeLock()

于 2012-07-19T08:50:59.733 に答える