這里我們先創建ObjLock類,並實現Runnable接口。並創建一個Demo類,具有被synchronized關鍵字修飾的非靜態方法與靜態方法。
非靜態方法
public class ObjLock implements Runnable { Demo demo; public ObjLock(Demo demo){ this.demo = demo; } public void run() { demo.getI(Thread.currentThread().getName()); } public static void main(String[] args){ Demo demo = new Demo(1); Thread thread = new Thread(new ObjLock(demo),"thread0"); Thread thread1 = new Thread(new ObjLock(demo),"thread1"); Thread thread2 = new Thread(new ObjLock(new Demo(2)),"thread2"); thread.start(); thread1.start(); thread2.start(); } } class Demo{ static int i; Demo(int i){ this.i=i; } public static synchronized void staticGetI(String s){ for (int j=0;j<10000;j++){ System.out.println(i+"---------"+s); } } public synchronized void getI(String s){ for (int j=0;j<10000;j++){ System.out.println(i+"---------"+s); } } }
運行程序,可以看到如下結果:
1---------thread0 1---------thread0 2---------thread2 1---------thread0 2---------thread2 1---------thread0 1---------thread1 1---------thread1 2---------thread2 1---------thread1 1---------thread1 1---------thread1
可以看到Thread0和Thread2交替出現,Thread1和Thread2交替出現,但Thread0和Thread1不會交替出現。
因為對非靜態方法加鎖,實際上是對調用該方法的對象加鎖。Thread0和Thread1用的是同一個對象,所以互斥,但是Thread2則不受影響。
靜態方法
將getI方法改成static之后
public void run() { demo.staticGetI(Thread.currentThread().getName()); }
測試發現三個線程均互斥。
當synchronized修飾一個static方法時,多線程下,獲取的是類鎖(即Class本身,注意:不是實例),作用范圍是整個靜態方法,作用的對象是這個類的所有對象。
一個對象在兩個線程中分別調用一個靜態同步方法和一個非靜態同步方法
修改代碼
public void run() { if (Thread.currentThread().getName().equals("thread0")){ demo.staticGetI(Thread.currentThread().getName()); }else if (Thread.currentThread().getName().equals("thread1")){ demo.getI(Thread.currentThread().getName()); } }
結果:不會產生互斥。
解釋:因為雖然是一個對象調用,但是兩個方法的鎖類型不同,調用的靜態方法實際上是類對象在調用,即這兩個方法產生的並不是同一個對象鎖,因此不會互斥,會並發執行。