synchronized 是java語言關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多隻有一個線程執行該段代碼。synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。
本文直接以代碼的形式來展示 synchronized 關鍵字的使用:
【1】synchronized Demo1:
package com.andyidea.demo;/** * 當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時, * 一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼 * 塊以後才能執行該代碼塊。 * @author Andy.Chen * */public class Thread01 implements Runnable {@Overridepublic void run() {synchronized (this) {for(int i=0;i<3;i++){System.out.println(Thread.currentThread().getName()+" synchronized loop "+i);}}}public static void main(String[] args) {Thread01 t01 = new Thread01();System.out.println("Welcome to Andy.Chen Blog! \n" +"synchronized 關鍵字使用 \n" +"--------------------------");Thread ta = new Thread(t01,"A");Thread tb = new Thread(t01,"B");ta.start();tb.start();}}
運行結果如下:
Welcome to Andy.Chen Blog! synchronized 關鍵字使用 --------------------------B synchronized loop 0B synchronized loop 1B synchronized loop 2A synchronized loop 0A synchronized loop 1A synchronized loop 2
【2】synchronized Demo2:
package com.andyidea.demo;/** * 當一個線程訪問object的一個synchronized(this)同步代碼塊時, * 另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。 * @author Andy.Chen * */public class Thread02 {public void method01(){synchronized (this) {int i=0;while(i++ < 3){System.out.println(Thread.currentThread().getName() +":"+ i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}public void method02(){//第1種方式:當一個線程訪問object的一個synchronized(this)同步代碼塊時,//另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。//int j=0;//while(j++ < 3){//System.out.println(Thread.currentThread().getName() +":"+ j);//try {//Thread.sleep(1000);//} catch (InterruptedException e) {//e.printStackTrace();//}//}//第2種方式:當一個線程訪問object的一個synchronized(this)同步代碼塊時,//其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。synchronized (this) {int j=0;while(j++ < 3){System.out.println(Thread.currentThread().getName() +":"+ j);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}/** * 當一個線程訪問object的一個synchronized(this)同步代碼塊時, * 它就獲得了這個object的對象鎖。 * 結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。 */public synchronized void method3(){int k=0;while(k++ < 3){System.out.println(Thread.currentThread().getName() +":"+ k);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {final Thread02 t02 = new Thread02();System.out.println("Welcome to Andy.Chen Blog! \n" +"synchronized 關鍵字使用 \n" +"--------------------------");Thread t02A = new Thread(new Runnable() {@Overridepublic void run() {t02.method01();}},"A");Thread t02B = new Thread(new Runnable() {@Overridepublic void run() {t02.method02();}},"B");Thread t02C = new Thread(new Runnable() {@Overridepublic void run() {t02.method3();}},"C");t02A.start();t02B.start();t02C.start();}}
運行結果如下:
Welcome to Andy.Chen Blog! synchronized 關鍵字使用 --------------------------B:1B:2B:3C:1C:2C:3A:1A:2A:3
【3】synchronized Demo3:
package com.andyidea.demo;/** * synchronized對象鎖 * @author Andy.Chen * */public class Thread03 {class InnerObject{/** * 內部類方法1 */private void innerMethod01(){int i=0;while(i++ < 3){System.out.println(Thread.currentThread().getName() +":"+ i);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}/** * 內部類方法2 */private void innerMethod02(){int j=0;while(j++ < 3){System.out.println(Thread.currentThread().getName() +":"+ j);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}/** * 外部類方法1 * @param innerObj */private void outerMethod01(InnerObject innerObj){synchronized (innerObj) {innerObj.innerMethod01();}}/** * 外部類方法2 * @param innerObj */private void outerMethod02(InnerObject innerObj){innerObj.innerMethod02();}public static void main(String[] args) {final Thread03 t03 = new Thread03();final InnerObject innerObj = t03.new InnerObject();System.out.println("Welcome to Andy.Chen Blog! \n" +"synchronized 關鍵字使用 \n" +"--------------------------");Thread t03A = new Thread(new Runnable() {@Overridepublic void run() {t03.outerMethod01(innerObj);}},"A");Thread t03B = new Thread(new Runnable() {@Overridepublic void run() {t03.outerMethod02(innerObj);}},"B");t03A.start();t03B.start();}}
運行結果如下:
Welcome to Andy.Chen Blog! synchronized 關鍵字使用 --------------------------A:1B:1B:2A:2B:3A:3
總結:
1. synchronized 方法控制對類成員變數的訪問:每個類執行個體對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類執行個體的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨佔該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的線程方能獲得該鎖,重新進入可執行狀態。這種機制確保了同一時刻對於每一個類執行個體,其所有聲明為 synchronized 的成員函數中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類執行個體對應的鎖),從而有效避免了類成員變數的存取違規(只要所有可能訪問類成員變數的方法均被聲明為
synchronized)。
2. synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類執行個體或類)的鎖方能執行。由於可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。
對synchronized(this)的一些理解
一、當兩個並發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。
二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
四、當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。