2017-07-28 12 views
3

Bazはワーカーの実装で、次のようなAPIがあります。 このBarはスレッドセーフである必要があります。これは、Bazのコールバックとやりとりするときには厄介です。デッドロックが同期コールバックを起こさないようにスレッドセーフを維持

現在のbazインスタンスは、コールバック(ワーカースレッド上で呼び出すことも同期して呼び出すこともできます)で参照する必要があります。 コメントは、問題が表示されるはずです:

final class Bar { 
    final Lock lock = new ReentrantLock(); 
    Baz baz; // Guarded by lock. 

    void run() { // Called by any thread. 
    lock.lock(); 
    if (baz.isRunning()) { 
     lock.unlock(); 
     return; 
    } 
    baz = new Baz(); 
    // If it unlocks here, the next line may execute on the wrong Baz. 
    // If it doesn't unlock here, there will be a deadlock when done() is called synchronously. 
    // lock.unlock(); 
    baz.run(new Baz.Callback() { // May be called synchronously or by Baz worker thread. 
     @Override 
     public void done() { 
     lock.lock(); 
     baz = new Baz(); 
     lock.unlock(); 
     } 
    }); 
    } 
} 

も、デッドロックが生じないながら正しく、この作品を作るための良い方法はありますか?

編集:もっと簡潔に:あなたが達成しようとしているものを得るcompletellyする

final class Foo { 
    final Lock lock = new ReentrantLock(); 

    void run() { 
    lock.lock(); 
    worker.enqueue(new Callback() { 
     @Override void complete() { 
     lock.lock(); // Could cause deadlock. 
     } 
    }); 
    lock.unlock(); 
    } 
} 

答えて

0

わからないが、多分これはあなたが探しているものでしょうか?

final class Bar { 
    final Lock lock = new ReentrantLock(); 
    Baz baz = new Baz(); 

    void run() { 
     if (!lock.tryLock()) { 
      return; 
     } 
     try { 
      CountdownLatch callbackFlag = new CountdownLatch(1); 
      baz.run(new Baz.Callback() { 
       @Override 
       public void done() { 
        callbackFlag.countDown(); 
       } 
      }); 
      try { 
       callbackFlag.await(); // better use overloaded method with max timeout waiting. you don't probably want to wait forever 
       baz = new Baz(); // do you really want to reinit Baz on each execution? 
      } catch (InterruptedException e) { 
       // decide what you want to happen here 
      } 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 
+0

しかし、baz割り当てはコールバックにある必要があります。明確にするために –

+0

が編集されました。 –

+0

なぜコールバックで参照されるべきですか?私が投稿したコードは、コールバックが完了するまで、bazが再初期化されないようにします。もしも本当に必要ならば、 –

関連する問題