1

次のことの理解は何でしょうか?
私はSOでこの投稿を読みましたが、それでも組み立てるのに途方に暮れています。

code1:

synchronized(this){ 
// some code
}

code2:

Object lock = new Object();

synchronized(lock){
// some code
}

チュートリアル、または子供に説明するように同期して説明するためのリンクはありますか?

4

4 に答える 4

6

基本的に、Javaのすべてのオブジェクトに関連付けられた「ロック」があります。

スレッドがsynchronized(something)の呼び出しに到達すると、続行する前に何かのロックを取得する必要があります。一度に1つのスレッドのみがオブジェクトの状態を変更できるようにする場合、最も明白なことは、そのオブジェクトのロックで同期することです。異なるメソッドを並行して呼び出すことが許可されている場合は、そのために異なるロックが必要です。

同期(this)、または単に同期を書き込む場合、スレッドは現在のオブジェクト(メソッドが呼び出される)に関連付けられたロックを取得する必要があります。

Java 5.0以降、並行パッケージは同期の代わりに使用できる適切なロックを提供することに注意してください。

于 2009-08-30T15:23:23.730 に答える
3

ブロック内にコードを配置するsynchronizedということは、基本的に、「このコードの実行が開始されると、このオブジェクトを使用する必要のある他のコードを同時に実行することはできない」という意味です。

したがって、スレッド#2がcode2ブロック内でコードを実行している場合、コードに関しては、他のすべてのスレッドを効果的に調べて、現時点でオブジェクトsynchronized(lock)と「同期された」コードを実行している人がいないことを確認する必要があります。lockスレッド#1は確かに同時にいくつかのコードを実行していますが、完全に無関係なコードである可能性があります。some codeもしそうなら、スレッド#2があなたの" "のものを実行し始めるのは安全です。

一方、スレッド#1がsynchronized(this)ブロックに到達した場合、スレッド#1も一時停止して、他のスレッドがを使用しているかどうかを確認する必要がありますthisthisがと同じオブジェクトの場合lock、問題があります。同時に(同期ブロック内で)そのオブジェクトを使用できるのは1つのスレッドだけである可能性があると言われました。しかし、スレッド#2はすでにそれを使用しています。スレッド#1はただ待つ必要があります...そして待つ...そして待つ...最終的にスレッド#2が終了するまで。その後、先に進むことができます。

その結果synchronized、一度に実行できるブロックは1つだけになります(もちろん、特定のオブジェクトを使用します)。

于 2009-08-30T15:29:30.707 に答える
3

すでに与えられた優れた回答で言及されていないことの1つは、code1とcode2の違いです。code1 では、コードが見つかったオブジェクトのインスタンスで同期が行われ、code2 では、オブジェクト内の特定のロック オブジェクトで同期が行われます。

外側のクラスに 2 つの同期ブロックしかない場合、2 つの機能に違いはありませんが、次の点を考慮してください。

クラスCodeOneClass {
  ...
  synchronized(this) { // または単に「同期済み」 - デフォルトはこれ
      最初の保護されたコード ブロック
  }
  ...
  同期(これ){   
      2 番目の保護されたコード ブロック
  }
...
}

クラスCodeTwoClass {
  ...
  オブジェクト lock1 = 新しいオブジェクト();
  同期 (ロック 1) {   
      最初の保護されたコード ブロック
  }
  ...
  オブジェクト lock2 = 新しいオブジェクト();
  同期 (ロック 2) {   
      2 番目の保護されたコード ブロック
  }
...
}

2 つのスレッドが CodeOneClass の同じインスタンスを使用しようとしている場合、2 つの保護されたコード ブロックのいずれかに同時に存在できるのはそのうちの 1 つだけです。

しかし、2 番目のイディオムを使用すると、1 つのスレッドが最初の保護されたブロックにあり、別のスレッドが別のブロックにあることが安全であると柔軟に言うことができます。ロックが同じ (両方とも同じロック オブジェクトで同期している) 場合、動作は最初のようになることに注意してください。

他にも違いがあります。一部のライターは、 synchronized(this)の問題を指摘し始めています。ここで、SO に関する別の投稿を紹介します: Java で Synchronized(this) を回避しますか?

この記事と、リンク先の 3 つの投稿を読むことを強くお勧めします。

于 2009-08-30T16:16:26.807 に答える
2

次のメソッドを持つ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チュートリアルは、並行性とロックに関する情報を開始するのに適した場所です。

于 2009-08-30T15:35:44.563 に答える