質問
次のことはどのような理解でしょうか?
私は通過してきました これ SOに投稿しましたが、組み立てにまだ迷っています。
コード1:
synchronized(this){
// some code
}
コード2:
Object lock = new Object();
synchronized(lock){
// some code
}
子供に説明するように同期を説明するチュートリアルやリンクはありますか?
解決
すでに与えそう優れた答えに記載されていないことの一つは、CODE1とCODE2間の違いがあります。 CODE1では、同期コードが発見されたオブジェクトのインスタンスにあり、CODE2では、オブジェクト内の特定のロックオブジェクトでいます。
包含するクラスで唯一の2つのsynchronizedブロックがある場合、、そこに2の間には、の機能の違いはませんが、これを検討します:
をclass CodeOneClass { ... synchronized(this) { // or merely "synchronized" - it defaults to this first protected code block } ... synchronized(this) { second protected code block } ... } class CodeTwoClass { ... Object lock1 = new Object(); synchronized(lock1) { first protected code block } ... Object lock2 = new Object(); synchronized(lock2) { second protected code block } ... }
2つのスレッドがそれらの一方のみが、同時に2つの保護されたコードブロックののののいずれかにすることができ、CodeOneClassの同じインスタンスを使用しようとしている場合。
しかし、第二イディオムでは、1つのスレッドが最初に保護されたブロックにあるように、そして他は他にもすることは安全だと言って柔軟性を持っています。ロックは(両方が同じロックオブジェクトで同期)、同じであれば、動作は最初のようであろうことに留意されたい。
他の違いがあります。 :私はSOにここで別のポストにあなたを指すことになり - いくつかの作家は(この)のの同期の問題を指摘し始めています 避けJavaで(この)同期には
私は非常にそれを読んでお勧めします、そしてそれはにリンク3つのポスト。
他のヒント
基本的に、Java のすべてのオブジェクトには「ロック」が関連付けられています。
スレッドが synchronized(something) の呼び出しに到達すると、続行する前に何かのロックを取得する必要があります。一度に 1 つのスレッドだけがオブジェクトの状態を変更できるようにしたい場合、最も明白なのは、そのオブジェクトのロックを同期することです。異なるメソッドの並行呼び出しが許可されている場合は、そのために異なるロックが必要です。
synchronized(this) または単に synchronized と記述する場合、スレッドは、(メソッドが呼び出される) 現在のオブジェクトに関連付けられたロックを取得する必要があります。
Java 5.0 以降、並行パッケージでは適切な機能が提供されることに注意してください。 ロック これは同期の代わりに使用できます。
synchronized
ブロック内のコードを置くが、本質的に、意味
だから、スレッド#2は、あなたのcode2
ブロック内のコードを実行している場合、それはsynchronized(lock)
コードに来るとき、それが効果的に誰もがlock
オブジェクトで「同期」のコードを実行されていないことを確認するために他のすべてのスレッドで見て回る必要があり現時点では。スレッド#1は確かに同時にをいくつかのコードを実行されているが、それは完全に無関係なコードであるかもしれません。もしそうなら、それはあなたの「some code
」ものの実行を開始するスレッド#2のために安全です。
synchronized(this)
ブロックに取得する場合一方、それはあまりにも一時停止し、他のスレッドがthis
を使用しているかどうかを確認する必要があります。 this
がlock
と同じオブジェクトであるならば、我々は問題を抱えています。私たちは、1つのスレッドが、おそらく同時に(同期ブロックで)そのオブジェクトを使用することができることを言われました。しかし、スレッド#2は、すでにそれを使用しています。スレッド#1は、ちょうど最終的に#2が終了スレッドまで... ...待って待って...と待機する必要があります。その後、我々は進むことができます。
最終的な結果は、唯一のsynchronized
ブロックが(もちろん、特定のオブジェクトに)一度に実行できることである。
あなたが持っていると仮定します Account
メソッドを持つオブジェクト:
void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
if (accountBalance >= debitAmount) {
accountBalance -= debitAmount;
beneficiary.credit(debitAmount);
}
else {
throw new InsufficientFundsException();
}
}
ここで、残高 100 ユーロの口座があり、70 ユーロの引き落としが 2 回試行されたとします。2 つの引き落としが同時に発生した場合、 競合状態 このような:
- 最初の引き落としでは口座残高がチェックされます。100 >= 70、成功
- 2 番目の引き落としでは口座残高がチェックされます。100 >= 70、成功
- 最初の借方は実行されます。口座残高が30になる
- 2 番目の借方を実行します。口座残高が-40になります。 許されるべきではない
を同期することで、この悲惨な状況を防ぐことができます。 Account
オブジェクトのロック:
void debit(long debitAmount, Account beneficiary) throws InsufficientFundsException
{
synchronized (this) {
if (accountBalance >= debitAmount) {
accountBalance -= debitAmount;
beneficiary.credit(debitAmount);
}
else {
throw new InsufficientFundsException();
}
}
}
これにより、口座残高と借方のテストが口座残高の別のテストによって中断されることがなくなります。
の Sun Java チュートリアル 同時実行性とロックについての情報を得るには、ここから始めるのが良いでしょう。