Java のオブジェクト ロックとクラス ロックの比較 (同期)

Java では、同期されたコード ブロックは一度に 1 つのスレッドによってのみ実行できます。さらに、Java はマルチスレッドの同時実行をサポートします。これにより、2 つ以上のスレッドが同じフィールドまたはオブジェクトに同時にアクセスする可能性があります。

同期は、実行中のすべてのスレッドの同期を維持するプロセスです。同期により、共有メモリのビューの不一致によるメモリ整合性エラーが回避されます。メソッドがsynchronziedとして宣言されている場合、スレッドはメソッド オブジェクトのモニター オブジェクトまたはロック オブジェクトを保持します。別のスレッドが同期メソッドを実行している場合、そのスレッドがモニターを解放するまで、スレッドはブロックされます。

クラスで定義されたメソッドまたはブロックで synchronized キーワードを使用できることに注意してください。クラス定義では、synchronized キーワードを変数またはプロパティとともに使用することはできません。

1. Java のオブジェクト レベルのロック


オブジェクト レベルのロックは、非静的メソッドまたは非静的コード ブロックを同期して、特定のクラス インスタンスのコード ブロックを 1 つのスレッドだけが実行できるようにするためのメカニズムです。これは、インスタンス レベルのデータ スレッドの安全性を確保するために常に行う必要があります。

オブジェクトレベルのロックは次のように実行できます。

public class DemoClass
{
  public synchronized void demoMethod(){}
}
 
or
 
public class DemoClass
{
  public void demoMethod(){
    synchronized (this)
    {
      //other thread safe code
    }
  }
}
 
or
 
public class DemoClass
{
  private final Object lock = new Object();
  public void demoMethod(){
    synchronized (lock)
    {
      //other thread safe code
    }
  }
}

2. Javaにおけるクラスレベルロック(クラスレベルロック)


クラスレベルのロックは、実行時に複数のスレッドがクラスの使用可能なインスタンスの同期ブロックに入るのを防ぎます。これは、実行時に DemoClass のインスタンスが 100 個ある場合、どのインスタンスでも demoMethod() を実行できるのは一度に 1 つのスレッドだけであり、他のすべてのインスタンスは他のスレッドによってロックされることを意味します。

静的データ スレッドの安全性を確保するには、クラス レベルのロックを常に実行する必要があります。static キーワードがメソッドのデータをクラス レベルに関連付けることがわかっているため、静的フィールドまたはメソッドのロックを使用してクラス レベルに関連付けます。

public class DemoClass
{
  //Method is static
  public synchronized static void demoMethod(){
 
  }
}
 
or
 
public class DemoClass
{
  public void demoMethod()
  {
    //Acquire lock on .class reference
    synchronized (DemoClass.class)
    {
      //other thread safe code
    }
  }
}
 
or
 
public class DemoClass
{
  private final static Object lock = new Object();
 
  public void demoMethod()
  {
    //Lock object is static
    synchronized (lock)
    {
      //other thread safe code
    }
  }
}

3. オブジェクトレベルのロックとクラスレベルのロック - 重要な注意事項

  1. Java の同期では、同じロックを必要とする同期メソッドを 2 つのスレッドが同時に実行できないことが保証されます。
  2. Synchronized キーワードは、メソッドとコード ブロックでのみ使用できます。これらのメソッドまたはブロックは、静的または非静的にすることができます。
  3. スレッドが Java 同期メソッドまたはブロックに入るとロックを取得し、スレッドが同期メソッドまたはブロックから出るときは常にロックを解放します。完了後、またはエラーや例外によりスレッドが同期メソッドから離れた場合でも、ロックは解放されます。
  4. Java の synchronized キーワードは基本的にリエントラントです。つまり、同期メソッドが同じロックを必要とする別の同期メソッドを呼び出した場合、現在ロックを保持しているスレッドはロックを取得せずにメソッドに入ることができます。
  5. 同期されたブロックで使用されているオブジェクトが null の場合、Java 同期は NullPointerException をスローします。たとえば、上記のコード サンプルでは、​​ロックが null に初期化されている場合、「synchronized(lock)」は NullPointerException をスローします。
  6. Java の同期メソッドは、アプリケーションにパフォーマンスのコストを課します。したがって、どうしても必要な場合には同期を使用してください。また、同期されたコード ブロックを使用して、コードの重要なセクションのみを同期することを検討してください。
  7. 静的同期メソッドと非静的同期メソッドは、異なるオブジェクトをロックするため、同時に実行することもできます。
  8. Java 言語仕様によれば、synchronized キーワードはコンストラクターでは使用できません。これは違法であり、コンパイル エラーが発生します。
  9. Java の同期ブロックの非最終フィールドでは同期しないでください。なぜなら、非最終フィールドへの参照はいつでも変更される可能性があり、その場合、異なるスレッドが異なるオブジェクト上で同期する、つまりまったく同期しない可能性があるからです。
  10. 文字列リテラルはアプリケーション内の他の場所で参照される可能性があり、デッドロックが発生する可能性があるため、使用しないでください。new キーワードを使用して作成された文字列オブジェクトは安全に使用できます。ただし、ベスト プラクティスとして、新しいプライベート スコープ オブジェクト インスタンスを作成するか、それ自体を保護したい共有変数をロックします。[コメントでこれを指摘してくれた Anu に感謝します。

参考文献

Java のクラス レベル ロック - GeeksforGeeks

おすすめ

転載: blog.csdn.net/keeppractice/article/details/131828437