198

java.util.concurrentAPIは、と呼ばれるクラスを提供します。このクラスは、Lock基本的に、重要なリソースにアクセスするためにコントロールをシリアル化します。park()やなどのメソッドを提供しunpark()ます。

synchronizedキーワードとusingandwait()メソッドを使用できれば、同様のことができますnotify() notifyAll()

これらのどれが実際に優れているのか、そしてその理由は何ですか?

4

10 に答える 10

191

単にオブジェクトをロックしている場合は、使用することをお勧めしますsynchronized

例:

Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!

try{} finally{}どこでも明示的に行う必要があります。

同期を使用すると、非常に明確で間違いがありません。

synchronized(myObject) {
    doSomethingNifty();
}

とは言っても、Locks は、このようなクリーンな方法で取得および解放できない、より複雑なものに対してより役立つ場合があります。Lock正直なところ、そもそもベア s を使用することは避けたいと思います。必要に応じて、 aCyclicBarrierや aなどのより洗練された同時実行制御を使用します。LinkedBlockingQueue

wait()orを使用する理由はありませんでしたが、notify()良いものがあるかもしれません。

于 2010-11-17T05:18:56.000 に答える
72

これらのどれが実際に優れているのか、そしてその理由は何なのか疑問に思っています。

Lockand Condition(およびその他の新しいconcurrentクラス) は、ツールボックスの単なるツールであることがわかりました。古いクローハンマー(synchronizedキーワード)で必要なほとんどすべてのことを行うことができましたが、状況によっては使いにくいものでした. ツールボックスにツールを追加すると、これらの厄介な状況のいくつかがはるかに簡単になりました. ただし、私の古い爪ハンマーはまだ使用されています。

どちらかが本当に「優れている」とは思いませんが、それぞれがさまざまな問題により適していると思います。簡単に言えば、 のシンプルなモデルとスコープ指向の性質はsynchronized、コードのバグから私を保護するのに役立ちますが、同じ利点が、より複雑なシナリオでは障害となることがあります。これらのより複雑なシナリオに対処するために並行パッケージが作成されました。ただし、このより高いレベルの構造を使用するには、コード内でより明示的かつ慎重に管理する必要があります。

===

JavaDocは、 と の区別をうまく説明しているLockと思いますsynchronized(強調は私のものです)。

ロックの実装は、同期されたメソッドとステートメントを使用して取得できるよりも広範なロック操作を提供します。それらはより柔軟な構造化を可能にし、まったく異なるプロパティを持つことができ、複数の関連付けられた Condition オブジェクトをサポートすることができます。

...

同期されたメソッドまたはステートメントを使用すると、すべてのオブジェクトに関連付けられた暗黙的な監視ロックへのアクセスが提供されますが、すべてのロックの取得と解放がブロック構造の方法で強制的に行われます複数のロック取得された場合は、逆の順序で解放する必要があります。すべてのロックは、それらが取得されたのと同じレキシカル スコープで解放する必要があります

同期されたメソッドとステートメントのスコープ メカニズムにより、 モニター ロック を使用したプログラミングがはるかに簡単になり、ロックに関連する多くの一般的なプログラミング エラーを回避するのに役立ちますが、より柔軟な方法でロックを操作する必要がある場合があります。たとえば、同時にアクセスされるデータ構造をトラバースする* *一部のアルゴリズム*では、「hand-over-hand」または「チェーン ロック」を使用する必要があります。ノード A、次にノード B のロックを取得し、次に A を解放して C を取得します。次に B を解放し、D を取得します。Lock インターフェイスの実装により、さまざまなスコープでロックを取得および解放できるようにすることで、このような手法を使用できるようになります。複数のロックを任意の順序で取得および解放できます

この柔軟性の向上に伴い、追加の責任が伴います。ブロック構造のロックがないため、同期されたメソッドとステートメントで発生するロックの自動解放が削除されます。ほとんどの場合、次のイディオムを使用する必要があります。

...

ロックとロック解除が異なるスコープで発生する場合、ロックが保持されている間に実行されるすべてのコードがtry-finally または try-catch によって保護され、必要に応じてロックが解放されるように注意する必要があります。

ロックの実装は、ロックを取得するための非ブロック試行( tryLock ())、中断可能なロック取得の試行(lockInterruptively())、およびタイムアウトできるロック(tryLock(long, TimeUnit))。

...

于 2010-11-17T06:29:49.213 に答える
27

java.util.concurrentのユーティリティが実行するすべてのことをsynchronized、 、volatile、またはwait / notify などの低レベルのプリミティブで実現できます。

ただし、同時実行性には注意が必要であり、ほとんどの人は少なくともその一部を間違っており、コードを正しくないか非効率的 (またはその両方) にしています。

並行 API は、より簡単に (そしてより安全に) 使用できる高レベルのアプローチを提供します。synchronized, volatile, wait, notify一言で言えば、もう直接使用する必要はありません。

Lockクラス自体は、この ツールボックスの低レベル側にあり、それを直接使用する必要さえないかもしれません (ほとんどの場合Queuesセマフォなどを使用できます)。

于 2010-11-17T05:18:57.730 に答える
16

synchronizedまたはを使用する理由には、主に 4 つの要因がありますjava.util.concurrent.Lock

注: 固有ロックとは、同期ロックのことです。

  1. Java 5 で ReentrantLocks が登場したとき、組み込みロックと比べてかなり顕著なスループットの差があることが証明されました。より高速なロック メカニズムを探していて、1.5 を実行している場合は、jucReentrantLock を検討してください。Java 6 の組み込みロックは現在、同等です。

  2. jucLock には、ロックのためのさまざまなメカニズムがあります。Lock interruptable - ロックスレッドが中断されるまでロックを試みます。時限ロック - 一定時間ロックを試み、成功しない場合はあきらめます。tryLock - 他のスレッドがロックを保持している場合、ロックを試みます。これは、単純なロックとは別に含まれています。本質的なロックは単純なロックのみを提供します

  3. スタイル。1 と 2 の両方が、あなたが懸念しているカテゴリに当てはまらない場合、私を含むほとんどの人は、固有のロック セメナティクスが読みやすく、jucLock ロックよりも冗長ではないことに気付くでしょう。
  4. 複数の条件。ロックオンしたオブジェクトは、1 つのケースのみ通知され、待機することができます。Lock の newCondition メソッドを使用すると、1 つの Lock に、待機または通知する複数の理由を持たせることができます。実際にこの機能を実際に必要としているわけではありませんが、必要な人にとっては便利な機能です。
于 2010-11-17T14:43:59.573 に答える
6

主な違いは公平性です。言い換えると、リクエストはFIFOで処理されますか、それともバージングが発生する可能性がありますか?メソッドレベルの同期により、ロックの公平な割り当てまたはFIFO割り当てが保証されます。使用する

synchronized(foo) {
}

また

lock.acquire(); .....lock.release();

公平性を保証するものではありません。

ロックについて多くの競合がある場合、新しいリクエストがロックを取得し、古いリクエストがスタックするというバージングに簡単に遭遇する可能性があります。ロックのために200のスレッドが短い順序で到着し、2番目に到着したスレッドが最後に処理される場合があります。これは、一部のアプリケーションでは問題ありませんが、他のアプリケーションでは致命的です。

このトピックの詳細については、BrianGoetzの「JavaConcurrencyInPractice」の本のセクション13.3を参照してください。

于 2011-09-23T18:06:44.013 に答える
3

ロックはプログラマーの生活を楽にします。ロックで簡単に実現できる状況をいくつか紹介します。

  1. ある方法でロックし、別の方法でロックを解除します。
  2. ただし、2 つの異なるコードを処理する 2 つのスレッドがある場合、最初のスレッドでは、2 番目のスレッドで特定のコードを処理する必要があります (2 番目のスレッドで同じコードを処理する他のスレッドもいくつかあります)。同時スレッド)。共有ロックを使用すると、この問題を非常に簡単に解決できます。
  3. モニターの実装。たとえば、put メソッドと get メソッドが他の多くのスレッドから実行される単純なキューです。ただし、複数の put (または get) メソッドを同時に実行したり、put メソッドと get メソッドを同時に実行したりすることは望ましくありません。プライベートロックを使用すると、これを達成するのがずっと簡単になります。

一方、ロックと条件は同期メカニズムに基づいています。したがって、ロックを使用して実現できるのと同じ機能を確実に実現できます。ただし、同期を使用して複雑なシナリオを解決すると、作業が困難になり、実際の問題の解決から逸脱する可能性があります。

于 2016-06-16T01:09:53.980 に答える