あなたが提供した両方の例では、組み込みモニターが使用されています。ただし、2 番目の例では、フィールドの固有のロックを使用していset
ます。このプラクティスを使用するときは注意してください。 への参照を公開するとset
、クラス外のコードがそのモニターで同期され、デッドロックが発生する可能性があります。
あなたが得ている違いは、 APIsynchronized
の使用との違いだと思います。java.util.concurrent.Lock
得られるもののほとんどは、追加された柔軟性です ( Lockドキュメントから):
同期されたメソッドまたはステートメントを使用すると、すべてのオブジェクトに関連付けられた暗黙的な監視ロックへのアクセスが提供されますが、すべてのロックの取得と解放がブロック構造の方法で強制的に行われます。複数のロックが取得された場合は、逆の順序で解放する必要があります。すべてのロックは、ロックが取得されたのと同じレキシカル スコープで解放する必要があります。
同期されたメソッドとステートメントのスコープ メカニズムにより、監視ロックを使用したプログラミングがはるかに簡単になり、ロックに関連する多くの一般的なプログラミング エラーを回避するのに役立ちますが、より柔軟な方法でロックを操作する必要がある場合があります。たとえば、同時にアクセスされるデータ構造をトラバースするための一部のアルゴリズムでは、「hand-over-hand」または「チェーン ロック」を使用する必要があります。ノード A のロックを取得し、次にノード B を取得し、次に A を解放し、C を取得してから B を解放します。 Dなどを取得します。Lock インターフェイスの実装では、さまざまなスコープでロックを取得および解放したり、複数のロックを任意の順序で取得および解放したりできるため、このような手法を使用できます。
Lock API を使用してロックを取得する方法をさらに提供する 2 つのメソッド呼び出しもあります。
lockInterruptibly
: スレッドが中断されない限り、ロックを取得します。
tryLock
: 呼び出し時に解放されている場合にのみロックを取得します (オプションのタイムアウト)。
Java での並行性の標準的な参照は、「Java Concurrency in Practice」です。