JAvaのSynchronized(オブジェクトのロックとコードのロック)

3486 ワード

1、問題
Synchronizedロックは一般的に知られていますが、ロックオブジェクトかロックコードかをどのように区別しますか?
2、テストDemo
package leetcode.chenyu.test;

public class Synchronized {
	
	 class Test {
		public synchronized  void testFirst() {
			print("testFirst");
		}
		
		public void testSecond() {
			synchronized(this) {
				print("testSecond");
			}
		}
		
		public void testThird() {
			synchronized(Test.class) {
				print("testThird");
			}
		}
		
		public  void print(String method) {
			System.out.println(method + "start");
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(method + "end");
		}
	}
	
	
	class TestThread extends Thread {
		
		public int mType = 0;
		public Test mTest = null;
		
		public TestThread(int type, Test test) {
			this.mType = type;
			this.mTest = test;
		}
		
		public void run() {
			if (mTest == null) {
				if (mType == 1) {
					Test test = new Test();
					test.testFirst();
				}
				else if (mType == 2) {
					Test test = new Test();
					test.testSecond(); 
				} 
				else if (mType == 3) {
					Test test = new Test();
					test.testThird(); 
				}
			} else {
				if (mType == 1) {
					mTest.testFirst();
				}
				else if (mType == 2) {
					mTest.testSecond(); 
				}
				else if (mType == 3) {
					mTest.testThird(); 
				}
			}
		}
	}
	
	
	public static void main(String[] args) {
		Synchronized syn = new Synchronized();
		Test test = syn.new Test();
			for (int i = 0; i < 5; ++i) {
				syn.new TestThread(1, null).start();
		}
	}
}

3、運行結果と分析
1)、上記の運転結果による
testFirststart
testFirststart
testFirststart
testFirststart
testFirststart
testFirstend
testFirstend
testFirstend
testFirstend
testFirstend

2)、forループ内のコードを次のように変更します.
syn.new TestThread(2, null).start();

実行結果は次のとおりです.
testSecondstart
testSecondstart
testSecondstart
testSecondstart
testSecondstart
testSecondend
testSecondend
testSecondend
testSecondend
testSecondend

上記1)、2)、両方の場合、synchronized(this)およびstatic以外のsynchronizedメソッドでは、複数のスレッドが同じオブジェクトの同期コードセグメントを同時に実行することを防止するしかなく、ロックされているのはオブジェクト、すなわちロックされている自体thisであり、各スレッドに新しいオブジェクトが構築されているため、synchronizedがロックされていない.
3)、forループ内のコードを次のように変更します.
syn.new TestThread(1, test).start();
syn.new TestThread(2, test).start();

実行結果は次のとおりです.
testSecondstart
testSecondend
testSecondstart
testSecondend
testSecondstart
testSecondend
testSecondstart
testSecondend
testSecondstart
testSecondend

ここでは,我々のいくつかのフィールドが1つのオブジェクトを共有しているため,オブジェクトが固定されているため,ロックがロックされており,他のスレッドはロックを解放していない間に入らない.
4)、forループ内のコードを次のように変更します.
syn.new TestThread(3, null).start();
syn.new TestThread(3, test).start();

結果は以下の通りです.
testThirdstart
testThirdend
testThirdstart
testThirdend
testThirdstart
testThirdend
testThirdstart
testThirdend
testThirdstart
testThirdend

synchronized(Test.class)はグローバルロックの効果を実現し、オブジェクトが同じかどうかにかかわらず、同じ効果でコードをロックしました
私は普通これを使うのが多いです.
4、まとめ
1、synchronized非静的メソッドに追加する前とsynchronized(this)はこのクラスをロックしたオブジェクトであり、マルチスレッドアクセスでオブジェクトが異なるとロックできず、オブジェクトが1つ固定されているとロックできます.
2、synchronized(クラス名.class)と静的メソッドに追加する前に、コードブロックをロックし、マルチスレッドアクセス時にオブジェクトが同じかどうかにかかわらず、コードセグメントを縮小できる範囲をできるだけ縮小し、コードセグメントに同期を追加できるようにするには、メソッド全体に同期を追加しないで、ロックの粒度を縮小します.
4、まとめ