synchronizedの使用と説明


synchronizedの役割一、同期方法public synchronized void methodAAA(){
//….
}ロックされているのは、この同期メソッドを呼び出すオブジェクトです.
テスト:a、このキーワード修飾方法を使用せずに、2つのスレッドが同じオブジェクトを呼び出すこの方法.ターゲットクラス:
public class TestThread {
    public  void execute(){  //synchronized, 
         for(int i=0;i<100;i++){
            System.out.println(i);
        }    
    }
} 

スレッドクラス:
public class ThreadA implements Runnable{
    TestThread test=null;
    public ThreadA(TestThread pTest){  // , 
        test=pTest;
    }
    public void run() {
        test.execute();
    }
} 

呼び出し:
TestThread test=new TestThread();
Runnable runabble=new ThreadA(test);
Thread a=new Thread(runabble,"A");                
a.start();
Thread b=new Thread(runabble,"B");
b.start(); 

結果:出力された数字が交錯します.同期ではないことを示します.2つの方法は、異なるスレッドで非同期に呼び出されます.
b、目標クラスを修正し、synchronized修飾を増加する
public class TestThread {
    public synchronized  void execute(){  //synchronized 
        for(int i=0;i<100;i++){
            System.out.println(i);
        }    
    }
} 

結果:出力された数値は秩序化されており、まずAの数値を出力し、次にBであり、同期であることを示し、異なるスレッドであるが、2つの方法は同期呼び出しである.注:上記は2つの異なるスレッドですが、同じインスタンスオブジェクトです.次に、異なるインスタンスオブジェクトを使用してテストします.
c、各スレッドには独立したTestThreadオブジェクトがあります.ターゲットクラス:
スレッドクラス:
public class TestThread {
    public synchronized void execute(){  //synchronized 
        for(int i=0;i<100;i++){
            System.out.println(i);
        }    
    }
}

呼び出し:
TestThread test=new TestThread();   
Runnable runabble=new ThreadA(test);   
TestThread test2=new TestThread();   
Runnable runabble2=new ThreadA(test2);  
Thread a=new Thread(runabble,"A");                   
a.start();   
Thread b=new Thread(runabble2,"B");   
b.start();   

結果:出力された数字が交錯します.メソッドを修飾するためにsynchronizedキーワードを追加したが、異なるスレッドがそれぞれのオブジェクトインスタンスを呼び出し、2つのメソッドは依然として非同期であることを示した.
説明:このような複数のインスタンスについて、同期すなわち出力の数値が秩序正しくスレッド順に出力されるようにするには、静的変数を追加してロックすることができます(ロックされたオブジェクトについては後述します).
ターゲットクラスを変更するには、次の手順に従います.
public class TestThread {
    private static Object lock=new Object(); // 。
    public  void execute(){
        synchronized(lock){
            for(int i=0;i<100;i++){
                System.out.println(i);
            }    
        }
    }
} 

 
二、同期コードブロック
public void method(SomeObject so){
    synchronized(so)
       //…..
    }
} 

 
オブジェクトをロックします.実際にロックされているのは、オブジェクトの参照(object reference)がこのロックを手に入れると、その制御されたコードを実行することができます.ロックとして明確なオブジェクトがある場合は、上記のコードでプログラムを書くことができますが、ロックとして明確なオブジェクトがなく、コードを同期させたいだけである場合は、ロックとして特殊なinstance変数(オブジェクトでなければなりません)を作成することができます(上記の解決方法は、ステータスロックを追加することです).
a、オブジェクトをロックします.静的private byte[]lock=new byte[0];//特殊なinstance変数ターゲットクラス:
public class TestThread {
    private Object lock=new Object(); 
    public  void execute(){
        synchronized(lock){  // , lock, , , 。 lock
            for(int i=0;i<100;i++){
                System.out.println(i);
            }    
        }
    }
}   

実は上のロック方法は、次のようなものです.
public void execute(){  
    synchronized(this){   // 
        for(int i=0;i<100;i++){
            System.out.println(i);
        }    
    }
} 

 
b、オブジェクトが属するクラスpublic synchronized static void execute(){//...}をロックするオブジェクトまたはメソッドをロックします.に等しい
public class TestThread {
    public static void execute(){
        synchronized(TestThread.class){
            //
        }
    }
} 

 
テスト:
ターゲットクラス:
public class TestThread {
    private static Object lock=new Object();
    public synchronized static void execute(){  // 
        for(int i=0;i<100;i++){
            System.out.println(i);
        }    
    }
    public static void execute1(){
        for(int i=0;i<100;i++){
            System.out.println(i);
        }    
    }
    public void test(){
        execute();     // , 
        //execute1();  // , 
    }
} 

 
スレッドクラス:異なるメソッドを呼び出し、2つのスレッドクラスを構築します.
public class ThreadA implements Runnable{
    public void run() {
        TestThread.execute();// 
    }
}
public class ThreadB implements Runnable{
    public void run() {
        TestThread test=new TestThread();
        test.test();// 
    }
} 

 
呼び出し:
Runnable runabbleA=new ThreadA();
Thread a=new Thread(runabbleA,"A");                
a.start();
Runnable runabbleB=new ThreadB();
Thread b=new Thread(runabbleB,"B");                
b.start();  

 
注意:1、synchronizedでオブジェクトをロックするとき、このオブジェクトがロックコードセグメントで変更されると、このロックは消えます.次の例を参照してください.
ターゲットクラス:
public class TestThread {
    private static final class TestThreadHolder {
           private static TestThread theSingleton = new TestThread();
           public static TestThread getSingleton() {
               return theSingleton;
           }
           private TestThreadHolder() {
           }
         }
     
    private Vector ve =null;
    private Object lock=new Object();
    private TestThread(){
          ve=new Vector();
          initialize();
      }
    public static TestThread getInstance(){
        return TestThreadHolder.getSingleton();
      }
    private void initialize(){
        for(int i=0;i<100;i++){
              ve.add(String.valueOf(i));
          }
      }
    public void reload(){
        synchronized(lock){
              ve=null;            
              ve=new Vector();
                        //lock="abc"; 
            for(int i=0;i<100;i++){
                  ve.add(String.valueOf(i));
              }
          }
          System.out.println("reload end");
      }
    
    public boolean checkValid(String str){
        synchronized(lock){
              System.out.println(ve.size());
            return ve.contains(str);
          }
      }
}

説明:reloadメソッドとcheckValidメソッドにsynchronizedキーワードを追加し、lockオブジェクトをロックします.同じオブジェクトインスタンスのreloadメソッドとcheckValidメソッドは、異なるスレッドでそれぞれ呼び出されます.reloadメソッドでは、lockオブジェクト、すなわち注釈lock=「abc」は変更されません.その結果、reload endがコンソールから出力されてから100が出力されます.説明は同期呼び出しです.reloadメソッドでlockオブジェクトを変更するとコメントが削除され、最初に数値(現在のveのサイズ)が出力され、reload endが出力されます.説明は非同期呼び出しです.
2、単例モードにおけるマルチスレッドの考慮
public class TestThread {
     private static final class TestThreadHolder {
            private static TestThread theSingleton = new TestThread();
            public static TestThread getSingleton() {
                return theSingleton;
            }
            private TestThreadHolder() {
            }
        }
     private Vector ve =null;
     private Object lock=new Object();
     private TestThread(){
         ve=new Vector();
         initialize();
     }
     public static TestThread getInstance(){
         return TestThreadHolder.getSingleton();
     }
}

 
説明:内部クラスを追加し、内部クラスに静的オブジェクトを明示し、その単一クラスをインスタンス化し、初期化したデータはすべて単一クラスの構造関数で行われます.これにより、複数のインスタンスが同時にアクセスできることが保証され、初期化されたデータは正常に初期化されます.