Javaにおけるsynchronizedの使い方の詳細(4つの使い方)

5909 ワード

Java言語のキーワードは、メソッドまたはコードブロックを修飾するために使用される場合、同じ時点で最大1つのスレッドだけがセグメントコードを実行することを保証します.
 1.メソッド宣言に用いる、範囲オペレータ(publicなど)の後、タイプ宣言(voidなど)を返す前に置く.このとき、スレッドは、一度に1つのスレッドしかこのメソッドに入ることができず、他のスレッドがこのメソッドを呼び出すには、キューに並んで待つしかなく、現在のスレッド(synchronizedメソッド内部のスレッド)がこのメソッドを実行すると、他のスレッドが入る.
例:

   public synchronized void synMethod() {
    //   
   }

    2.あるコードブロックに対して使用する、synchronizedの後に括弧、括弧の中に変数があり、このようにして、一度に1つのスレッドだけがそのコードブロックに入る.このとき、スレッドはメンバロックを取得する.例:

   public int synMethod(int a1){
    synchronized(a1) {
     //           
    }
   }

    3.synchronizedの後ろの括弧にオブジェクトがある場合、スレッドはオブジェクトロックを得る.例:

 public class MyThread implements Runnable {
  public static void main(String args[]) {
  MyThread mt = new MyThread();
  Thread t1 = new Thread(mt, "t1");
  Thread t2 = new Thread(mt, "t2");
  Thread t3 = new Thread(mt, "t3");
  Thread t4 = new Thread(mt, "t4");
  Thread t5 = new Thread(mt, "t5");
  Thread t6 = new Thread(mt, "t6");
  t1.start();
  t2.start();
  t3.start();
  t4.start();
  t5.start();
  t6.start();
 }
 public void run() {
  synchronized (this) {
   System.out.println(Thread.currentThread().getName());
  }
 }
} 

3について、スレッドが入ると現在のオブジェクトロックが得る、他のスレッドはそのクラスのすべてのオブジェクトでの操作ができない.オブジェクトレベルでロックを使用するのは、通常、比較的粗い方法です.オブジェクト全体をロックし、他のスレッドが共有リソースにアクセスするためにオブジェクト内の他の同期メソッドを短く使用できないのはなぜですか?1つのオブジェクトに複数のリソースがある場合は、1つのスレッドにリソースの一部を使用させるだけで、すべてのスレッドを外部にロックする必要はありません.各オブジェクトにロックがあるため、以下のように仮想オブジェクトを使用してロックできます.

class FineGrainLock {
  MyMemberClass x, y;
  Object xlock = new Object(), ylock = new Object();
  public void foo() {
   synchronized(xlock) {
     //access x here
   }
   //do something here - but don't use shared resources
   synchronized(ylock) {
     //access y here
   }
  }
  public void bar() {
   synchronized(this) {
     //access both x and y here
   }
   //do something here - but don't use shared resources
  }
 }

 4.synchronizedの後ろの括弧にはクラスがあり、この場合、スレッドはオブジェクトロックを得る.例:

class ArrayWithLockOrder{
 private static long num_locks = 0;
 private long lock_order;
 private int[] arr;
 public ArrayWithLockOrder(int[] a)
 {
  arr = a;
  synchronized(ArrayWithLockOrder.class) {//-----  
   num_locks++;       //     1。
   lock_order = num_locks; //             lock_order。
  }
 }
 public long lockOrder()
 {
  return lock_order;
 }
 public int[] array()
 {
  return arr;
 }
 }
 class SomeClass implements Runnable
 {
 public int sumArrays(ArrayWithLockOrder a1,
            ArrayWithLockOrder a2)
 {
  int value = 0;
  ArrayWithLockOrder first = a1;    //          
  ArrayWithLockOrder last = a2;    //     。
  int size = a1.array().length;
  if (size == a2.array().length)
  {
   if (a1.lockOrder() > a2.lockOrder()) //           
   {                   //   。
    first = a2;
    last = a1;
   }
   synchronized(first) {       //           。
    synchronized(last) {
     int[] arr1 = a1.array();
     int[] arr2 = a2.array();
     for (int i=0; i 
 

4については、スレッドが入ると、静的変数と静的メソッドを含む、このクラスのスレッドのすべての動作は行うことができず、実際には、静的メソッドと静的変数を含むコードブロックの同期については、通常4でロックする.
PS:synchronized用法まとめ
synchronizedは、コードに与える影響を異なる場所で使用します.
1.synchronizedキーワード修飾方法
P 1,P 2が同じクラスの異なるオブジェクトであると仮定し,このクラスでは以下のような場合の同期ブロックや同期方法が定義されており,P 1,P 2はいずれもそれらを呼び出すことができる.

public synchronized void method(){
  // 
}

これが同期メソッドです.synchronizedがロックしているのは、この同期メソッドオブジェクトを呼び出すことです.すなわち、1つのオブジェクトP 1が異なるスレッドでこの同期方法を実行すると、それらの間に反発が形成され、同期の効果が得られる.同時に、オブジェクトに複数の同期メソッドがある場合、1つのスレッドが実行オブジェクトのsynchronizedメソッドを取得すると、オブジェクト内の他の同期メソッドも他のスレッドを実行できません.しかし、このオブジェクトが属するClassによって生成された別のオブジェクトP 2は、synchronizedキーワードが付加されたメソッドを任意に呼び出すことができる.
上記のサンプルコードは、次のコードと同じです.

public void method()  {  
  synchronized (this)   
  {  
    //..  
  }  
} 

今回は1つのP 1オブジェクトのオブジェクトロックであり,どれがP 1オブジェクトロックのスレッドを手に入れてこそ,P 1の同期方法を呼び出すことができるのか,P 2にとって,P 1というロックは彼とは無関係であり,プログラムもこのような状況で同期メカニズムの制御から脱し,データの混乱をもたらす可能性がある.
2.ブロックを同期します.サンプルコードは次のとおりです.

public void method() { 
synchronized (this) 
{ 
//.. 
} 
} 

この場合、ロックはsoというオブジェクトであり、各オブジェクトは一意のロックに対応するので、どのスレッドがこのオブジェクトロックを手に入れると、彼が制御しているコードを実行することができます.ロックとして明確なオブジェクトがある場合、このようにプログラムを書くことができますが、ロックとして明確なオブジェクトがなく、コードを同期させたいだけである場合、ロックとして特別なinstance変数(オブジェクトである必要があります)を作成することができます.

 private byte[] lock = new byte[0]; 
  Public void method(){  
      synchronized(lock) 
      { 
        // 
      }
  }  

注意:長さゼロのbyte配列オブジェクトを作成すると、どのオブジェクトよりも経済的になります.Dコンパイルされたバイトコードを表示します.長さゼロのbyte[]オブジェクトを生成するには3つの操作コードしか必要ありません.Object lock=new Object()には7行の操作コードが必要です.
3.static関数にsynchronizedを使用します.サンプルコードは次のとおりです.

Class Foo  
{  
  public synchronized static void method1()  

  {  
    //.  
  }  
  public void method2()  
  {  
    synchronized(Foo.class)  
    //
  }  
} 

両方の同期メソッドは、このメソッドのオブジェクトが属するクラスのクラスロックを呼び出します.(クラスでsynchronizedのstatic関数Aが定義され、synchronizedのinstance関数Bが定義されている場合、このクラスの同じオブジェクトObjがマルチスレッドでAとBにアクセスする2つのメソッドを区別する場合、同期は構成されません.なぜなら、彼らのロックは同じではないからです.AメソッドのロックはObjが属するClassで、BのロックはObjが属するこのオブジェクトです.