Synchronized同期静的方法と非静的方法の概要

5011 ワード

1.Synchronizedは非静的メソッドを修飾し、実際にはこのメソッドを呼び出すオブジェクトにロックをかけ、通称「オブジェクトロック」と呼ばれます.
Javaの各オブジェクトにはロックがあり、唯一です.仮に割り当てられた1つのオブジェクト空間を仮定すると、中には複数の方法があり、空間の中に複数の小さな部屋があることに相当します.もし私たちがすべての小さな部屋をロックすれば、このオブジェクトには鍵が1つしかないので、同じ時間に1人だけ小さな部屋を開けて、使い終わったら返して、JVMから次の鍵を手に入れた人を割り当てます.
ケース1:同じオブジェクトが2つのスレッドでそれぞれそのオブジェクトにアクセスする2つの同期方法
結果:反発が発生します.
説明:ロックはオブジェクトを対象としているため、オブジェクトがsynchronizedメソッドを呼び出すと、他の同期メソッドは実行が終了し、ロックが解放されるまで待機する必要があります.
ケース2:異なるオブジェクトが2つのスレッドで同じ同期メソッドを呼び出す
結果:反発は発生しません.
解釈:2つのオブジェクトであるため、ロックはオブジェクトに対して行われ、メソッドではないので、同時に実行することができ、反発しません.イメージ的には、各スレッドがメソッドを呼び出すときにnewのオブジェクトであるため、2つの空間、2つの鍵が現れます.
2.Synchronizedは静的方法を修飾し、実際にはこのクラスオブジェクトにロックをかけ、通称「クラスロック」と呼ばれている.
ケース1:クラスで2つの異なる同期メソッドを直接2つのスレッドで呼び出す
結果:反発が発生します.
静的オブジェクトにロックをかけるのは実际にクラス(.class)にロックをかけるため、クラスオブジェクトは1つしかなく、いつでも1つの空间しかなく、中にはNつの部屋があり、1つのロックがあるので、部屋(同期方法)の间には反発するに违いない.
注意:上記の状況は、単一のインスタンス・モードでオブジェクトを宣言して非静的メソッドを呼び出す場合と同じです.これは、常にこのオブジェクトしかないためです.したがって、アクセス同期メソッド間では反発するに違いありません.
ケース2:1つのクラスの静的オブジェクトで2つのスレッドで静的メソッドまたは非静的メソッドを呼び出す
結果:反発が発生します.
説明:オブジェクト呼び出しなので、上と同じです.
ケース3:1つのオブジェクトが2つのスレッドでそれぞれ1つの静的同期メソッドと1つの非静的同期メソッドを呼び出す
結果:反発は発生しません.
解釈:1つのオブジェクト呼び出しですが、2つのメソッドのロックタイプが異なるため、呼び出された静的メソッドは実際にはクラスオブジェクトが呼び出されています.つまり、この2つのメソッドが生成したのは同じオブジェクトロックではないので、反発せずに同時実行されます.
テストコード:
同期メソッドクラス:SynchronizedTest.java
public class SynchronizedTest {
	/*private SynchronizedTest(){}
	private static SynchronizedTest st;           //       ,     ,   synchronized  
	public static SynchronizedTest getInstance(){
		if(st == null){
			st = new SynchronizedTest();
		}
		return st;
	}*/
	/*private SynchronizedTest(){}
	private static final SynchronizedTest st = new SynchronizedTest();  //       ,      
	public static SynchronizedTest getInstance(){
		return st;
	}*/
	
	public static SynchronizedTest staticIn = new SynchronizedTest();   //    
	
     public synchronized void method1(){                                      //     1
    	 for(int i = 0;i < 10;i++){  
    		 System.out.println("method1 is running!");
    		 try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	 }
     }
     public synchronized void method2(){                                   //     2
    	 for( int i = 0; i < 10 ; i++){
    		 System.out.println("method2 is running!");
    		 try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	 }
     }
    public synchronized static void staticMethod1(){                     //    1
    	for( int i = 0; i < 10 ; i++){
   		 System.out.println("static method1 is running!");
   		 try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
   	 }
    }
    public synchronized static void staticMethod2(){                      //    2
    	for( int i = 0; i < 10 ; i++){
   		 System.out.println("static method2 is running!");
   		 try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
   	 }
    }
}

スレッドクラス1:Thread 1.JAva(異なるコメントを解放して異なる状況をテストできる)
public class Thread1 implements Runnable{

	@Override
	public void run() {
//		SynchronizedTest s = SynchronizedTest.getInstance();
//		s.method1();
//		SynchronizedTest s1 = new SynchronizedTest();
//		s1.method1();
		SynchronizedTest.staticIn.method1();

//		SynchronizedTest.staticMethod1();
//		SynchronizedTest.staticMethod2();
	}
}

スレッドクラス2:Thread 2.Java
public class Thread2 implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
//		SynchronizedTest s = SynchronizedTest.getInstance();
//		SynchronizedTest s2 = new SynchronizedTest();
//		s2.method1();
//		s.method2();
//		SynchronizedTest.staticMethod1();
//		SynchronizedTest.staticMethod2();
//		SynchronizedTest.staticIn.method2();
		SynchronizedTest.staticIn.staticMethod1();
	}
}

主なクラス:ThreadMain.java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadMain {
	public static void main(String[] args) {
	Thread t1 = new Thread(new Thread1());
        Thread t2 = new Thread(new Thread2());
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(t1);
        exec.execute(t2);
        exec.shutdown();
	}

}

まとめ:
    1.オブジェクトロックキーは、共有変数の一意性を保証するために、反発するには1つしかありません.
    2.静的メソッドのロックは、インスタンスメソッドのロックとデフォルトでは同じではありません.同期に2つのロックを設定する必要がある場合は、同じではありません.
    3.同じクラスのメソッド上のロックについては、メソッドを呼び出すオブジェクトから来ており、メソッドを呼び出すオブジェクトが同じであれば、ロックは必然的に同じであり、そうでなければ異なる.例えばnew A().x()とnew A().x()は,対象が異なり,ロックが異なり,Aの単利であれば反発できる.
    4.静的メソッドロック、他のすべての静的メソッドロックと反発することができます
    5.静的方法ロックとxx.classロック効果と同様、直接クラスに属する