Synchronized 和 static synchronized 的區別

問題:static 修飾的Synchronized 方法和非 static Synchronized 方法區別?

 這個問題是一個同事在一次無意間中問過我的;在解釋之前,我們先來看兩個demo;我覺得通過代碼來講解釋最容易理解的:

demo1:

/**
 * 
 * @author leo-zeng
 *
 */
public class SynchronizedDemo {

	public static synchronized void staticTest() {
		for (int i = 0; i < 5; i++) {
			try {
				Thread.sleep(1000);
				System.out.println("static test"+Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	public synchronized void test() {
		for (int i = 0; i < 5; i++) {
			try {
				Thread.sleep(1000);
				System.out.println(" test"+Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		//SynchronizedDemo 類的兩個實例
		final SynchronizedDemo d1 = new SynchronizedDemo();
		final SynchronizedDemo d2 = new SynchronizedDemo();
		//線程1
		Thread thread1 = new Thread(new Runnable() {

			public void run() {
				d1.test();
			}
		}, "a");
		//線程2
		Thread thread2 = new Thread(new Runnable() {

			public void run() {
				d2.test();
			}
		}, "b");
		thread1.start();
		thread2.start();
	}
}
demo1 得到的結果是:

 testa
 testb
 testa
 testb
 testa
 testb
 testa
 testb
 testa
 testb

發現Synchronized 對於本例中並沒有起作用;

再看看demo2:

/**
 * 
 * @author leo-zeng
 *
 */
public class StaticSynchronizedDemo {

	public static synchronized void staticTest() {
		for (int i = 0; i < 5; i++) {
			try {
				Thread.sleep(1000);
				System.out.println("static test"+Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	public synchronized void test() {
		for (int i = 0; i < 5; i++) {
			try {
				Thread.sleep(1000);
				System.out.println(" test"+Thread.currentThread().getName());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		final StaticSynchronizedDemo d1 = new StaticSynchronizedDemo();
		final StaticSynchronizedDemo d2 = new StaticSynchronizedDemo();

		Thread thread1 = new Thread(new Runnable() {

			public void run() {
				StaticSynchronizedDemo.staticTest();
			}
		}, "b");

		Thread thread2 = new Thread(new Runnable() {

			public void run() {
				StaticSynchronizedDemo.staticTest();
			}
		}, "a");
		thread1.start();
		thread2.start();
	}
}
得到的結果:
static testb
static testb
static testb
static testb
static testb
static testa
static testa
static testa
static testa
static testa

發現 兩個線程被Synchronized 加上說了;線程同步走了; 爲什麼會這樣呢;其實從兩個例子就很好的回答了上面那個問題。

 synchronized是對類的當前實例進行加鎖,防止其他線程同時訪問該類的該實例的所有synchronized塊,記住看好了是該類的”當前實例“;demo1中 我們線程調用的是類的不同實例,所以synchronized對類的不同實例沒有約束。再看看demo2;static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。實際上,在類中某方法或某代碼塊中有 synchronized,那麼在生成一個該類實例後,改類也就有一個監視快,放置線程併發訪問改實例synchronized保護塊,而static synchronized則是所有該類的實例公用一個監視快了,也也就是兩個的區別了;可以總結說:synchronized 是 this.synchronized;而static synchronized 是類的synchronized;

拓展:

看下demo3

public class SynchronizedDemo3 {
	private final static Integer lock = new Integer(0);
	/**
	 * 靜態方法
	 */
	public static void staticTest(){
		//鎖住lock 對象
		synchronized (lock) {
			for (int i = 0; i < 3; i++) {
				try {
					Thread.sleep(1000);
					System.out.println(" static test"+Thread.currentThread().getName());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public  void test(){
		synchronized (lock) {
			for (int i = 0; i < 3; i++) {
				try {
					Thread.sleep(1000);
					System.out.println(" test"+Thread.currentThread().getName());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		final SynchronizedDemo3 s1 =new SynchronizedDemo3();
		final SynchronizedDemo3 s2 =new SynchronizedDemo3();
		
		Thread thread1 = new Thread(new Runnable() {

			public void run() {
				SynchronizedDemo3.staticTest();
			}
		}, "b");

		Thread thread2 = new Thread(new Runnable() {

			public void run() {
				s1.test();
			}
		}, "a");
		Thread thread3 = new Thread(new Runnable() {

			public void run() {
				s2.test();
			}
		}, "c");
		thread1.start();
		thread2.start();
		thread3.start();
	}
}
得到的結果就是 

 static testb
 static testb
 static testb
 testc
 testc
 testc
 testa
 testa
 testa

因爲Syssynchronized (lock) ;加在同一個object 對象上;所以就確保了類的所有對象都能約束到了。

y

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章