Synchronized,顧名思義,代表線程同步。那麼,在Java編程中如何使用它呢?
我們首先來看這樣一個情況:對於同一個變量synDemo,我們分別在2個不同的線程中調用synDemo.synMethord1()與synDemo.synMethord2()。
package com.cnblogs.gpcuster;/** * * @author Aaron.Guo * */
public class Tester {public static void main(String[] args) {final SynDemo synDemo = new SynDemo();Thread thread1 = new Thread() {@Overridepublic void run() {// TODO Auto-generated method stub
super.run();synDemo.synMethord1();}};Thread thread2 = new Thread() {@Overridepublic void run() {// TODO Auto-generated method stub
super.run();synDemo.synMethord2();}};thread1.start();thread2.start();while (true) {try {Thread.sleep(1000);System.out.println("main");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
我們的SynDemo是這樣定義的:
package com.cnblogs.gpcuster;/** * * @author Aaron.Guo * */
public class SynDemo{public void synMethord1() {while(true) {try {Thread.sleep(1000);System.out.println("synMethord1");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void synMethord2() {while(true) {try {Thread.sleep(1000);System.out.println("synMethord2");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
我們的SynDemo對象沒有任何特殊的定義,所以運行起來以後的情況如下:
synMethord2
synMethord1
main
synMethord2
synMethord1
main
synMethord2
synMethord1
接下來,我們給synMethord1添加上synchronized聲明,運行情況還是與上次一樣,因為我們只有一個線程在調用synMethord1的方法。
我們給synMethord2也添加上synchronized聲明,SynDemo對象的代碼修改為:
package com.cnblogs.gpcuster;/** * * @author Aaron.Guo * */
public class SynDemo{public synchronized void synMethord1() {while(true) {try {Thread.sleep(1000);System.out.println("synMethord1");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public synchronized void synMethord2() {while(true) {try {Thread.sleep(1000);System.out.println("synMethord2");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
這個時候,我們再運行程序,結果就不一樣了:
main
synMethord1
main
synMethord1
main
synMethord1
我們發現,對於SynDemo對象,只有synMethord1運行了,而synMethord2卻沒有運行。這是應為在方法級別的synchronized聲明將lock這個類對象的當前實例。所以在synMethord1運行結束unlock之前,當前實例是無法運行synMethord2的。這種方法級別的synchronized聲明和以下的做法是等同的:
package com.cnblogs.gpcuster;/** * * @author Aaron.Guo * */
public class SynDemo {public void synMethord1() {synchronized (this) {while (true) {try {Thread.sleep(1000);System.out.println("synMethord1");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public synchronized void synMethord2() {synchronized (this) {while (true) {try {Thread.sleep(1000);System.out.println("synMethord2");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
運行程序,結果與上次相同。
如果我們希望分別同步2個方法該如何處理?可以參考這個實現:
package com.cnblogs.gpcuster;/** * * @author Aaron.Guo * */
public class SynDemo {private Object flag1 = new Object();private Object flag2 = new Object();public void synMethord1() {synchronized (flag1) {while (true) {try {Thread.sleep(1000);System.out.println("synMethord1");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void synMethord2() {synchronized (flag2) {while (true) {try {Thread.sleep(1000);System.out.println("synMethord2");} catch (InterruptedException e) {// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
運行程序,結果如我們預期:
main
synMethord2
synMethord2
main
synMethord1
main
synMethord1
synMethord2
關於Synchronized還有一些其他的話題,如static的問題,繼承的問題,與volatile搭配使用等等,在網上都有很詳細的說明,這裡就不重復介紹了。