2011-01-27 18 views
3

ロックを保持しているスレッドが別のスレッドに渡すことができるタイプのロックを探しています。ここであるスレッドから別のスレッドに転送できるロック

は、私はそれをしたい理由です:

  • 私はConcurrentHashMapに似たクラスがある -
  • ほとんどの変更をロックするだけで一つのセグメントを必要とする複数のセグメントに分割され、特殊なコレクションを。いくつかの場合、2つのセグメントをロックする必要があります(具体的には、あるセグメントから別のセグメントに移動するようにキーを変更する必要があります)。
  • ほとんどの読み取りではロックは必要ありません。通常は揮発性読み取りで十分ですが、修正カウントチェックが失敗した場合、一度にセグメントは、
  • 検索が
  • ThreadPoolExecutorを経由して)複数のスレッドで行われていることが(例えば、それはエントリを逃してはいけない検索機能は、すべてのセグメントの一貫したビューを持つことが不可欠です
  • 検索タスク(単一セグメント用)は、いつでも中断することがあります。

ここで、検索メソッドがメインスレッドで呼び出され、すべてのセグメントをロックする必要があることがわかりました。すべてのセグメントロックは、(干渉がないことを保証するために)メインスレッドによって一度に保持されなければならないが、更新を行う主スレッドではなく、ワーカースレッドの1つである。したがって、一貫性のあるスナップショットがあることがわかると、メインスレッドにロックを「渡す」ようにしようとしています。

コレクション全体に単一のロックを使用していましたが、サイズが大きくなるにつれて、あまりにも多くの競合があったため、小さな更新では許容できないほど高い遅延が発生しました。

アンロックと再ロック(ReentrantLock)は安全ではありません。ワーカースレッドが検索を開始する前に別のスレッドがセグメントを変更する可能性があります。

プレーンSemaphoreは、異なるスレッドによるロックとロック解除を処理できます。発生する問題は誰がセマフォを解放すべきかです。ワーカースレッドは、ロックの所有権を獲得したことを通知する方法が必要です(このポイントの前後に例外がスローされ、メインスレッドがクリーンアップするかどうかを知る必要があるためです)セマフォの取得または解放が正しいスレッドで発生したかどうかを決して知ることができないため、単体テストも難しいでしょう。

私はと呼ばれるいくつかの Semaphoreの組み合わせと AtomicBooleanまたは AtomicReferenceを想像

ロックが他の方法でreentrantly使用することができればボーナスでしょう(それは、スレッド間で渡されていない。)が、クイックグーグル検索では例が明らかにならなかった。このアプローチを使用すべきではない理由はありますか?

+2

同時実行性は、単純なモデルで最も効果的です。説明の長さとモデルの複雑さを考えると、要件を簡素化することをお勧めします。 IMHOは効率的に動作する可能性が非常に高いです。私が知っている唯一の方法はUnsafe.park()とUnsafe.unpark(Thread)ですが、これらを直接使用することはお勧めしません。 –

+0

あなたが望むのは、トークンを渡すメカニズムを使わない理由で渡すことができる「ロック」です。それぞれのセグメントロックをトークンとして使用し、文字通り渡すことができますか?コレクションの検索時間が十分に長い場合、このトークンはロックされたファイルでもあります。メインスレッドは単にワーカースレッドに "ロック"を与えることができます。 – Fakrudeen

+0

ロックインのない方法でモデル化することは可能ですか?固定的な構造に連想的な "更新"を加え、代わりに新しい構造を作成することは可能ですか?あなたの解説はあなたが解決している根本的な問題ではなく、解決策です。 –

答えて

2

読み取り/書き込みロックを逆に使用すると動作する可能性があります。このイディオムでは、読み取りロックホルダは、データ構造(例えば、アレイ内の独立したスロット)への並行書き込みを実行する。書込みロックは、一貫した読取り(例えばアレイの加算)を実行するために排他的アクセスを獲得するために使用される。これはめったに使用されないイディオムですが、それらの奇妙なケースではエレガントです。あなたの問題はちょっと難しいですが、これは少なくとも具体的な解決策にインスピレーションを与えるかもしれません。私は、より深い理解があると思うが、問題は単純化され、古典的な解決策がより適切になるだろう。

+0

私が言ったように、 'ConcurrentHashMap'のソースを読むと、それがより明確になるかもしれません。私のクラスは 'contains(Object)'と同等のことをするときに、(潜在的に)異なるスレッド内の各セグメントを検索するという点を除けば、私のクラスは非常に似ています。質問を微調整して明確にすることができるかどうかがわかります。あなたのソリューションはうまくいくと思います。 – finnw

+0

私は技術的な側面は理解していますが、行動的な側面は理解していません。なぜキーが移動したのですか?なぜ検索しなければならないのですか(例えばConcurrentSkipListMapを使わない理由)法線マップと異なる契約とは何ですか? –

+0

単一の自然順序付けはありません。この検索操作は比較を「あいまい」にし、セグメント内のすべての要素をチェックして、最も近いものを探します。キーを変更すると、hashCodeが時々別のセグメントに属するように変更されます。移動中に検索から除外されないようにするには、それを原子的に移動する必要があります。 – finnw

関連する問題