Synchronized修飾非靜態方法,是對調用該方法的對象加鎖,俗稱“對象鎖”。
這裏的對象加鎖並非是說執行該加鎖方法的時候整個對象的所有成員都不允許其他線程訪問了,
而是說該對象內所有的加鎖的非靜態方法共用這一把鎖, 一個加鎖非靜態方法執行, 另一個加鎖非靜態方法不能執行,要等持有鎖的線程釋放鎖, 不同對象之間的方法不互相作用
這裏舉第一個例子:
兩個線程執行同一個對象的不同加鎖非靜態方法, 預期互斥執行,即同一對象的兩個加鎖的非靜態方法共用該鎖:
package test;
public class Test1 {
synchronized void fun1() throws InterruptedException {
System.out.println("加鎖的方法1開始執行");
Thread.sleep(2000);
System.out.println("加鎖的方法1執行結束");
}
synchronized void fun2() throws InterruptedException {
System.out.println("加鎖的方法2開始執行");
Thread.sleep(2000);
System.out.println("加鎖的方法2執行結束");
}
}
兩個線程分別執行同一個對象的兩個方法
package test;
public class TestSyntro {
public static void main(String[] args) {
Test1 obj1=new Test1();
new Thread() {
@Override
public void run() {
try {
obj1.fun1();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
new Thread() {
@Override
public void run() {
try {
obj1.fun2();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
}
}
結果:
說明兩個方法是互斥執行的, 共用一把鎖
那麼我們把第二個方法的鎖去掉,看看同一個對象加鎖的方法運行時不加鎖的方法是否可以執行:
(由於篇幅,以後例子都由上例微改得到, 不再重複貼代碼, 也是因爲本來就是給新手看, 太長反而讓人暈,注意描述,加鎖與否, 幾個對象,靜態,非靜態)
說明同一對象加鎖方法不影響爲加鎖的方法
我們用兩個線程執行兩個對象的加鎖方法, 預期不互斥, 證明不同對象不共用非靜態鎖:
只是改了第二個線程的執行方法的對象:
package test;
public class TestSyntro {
public static void main(String[] args) {
Test1 obj1=new Test1();
Test1 obj2=new Test1();
new Thread() {
@Override
public void run() {
try {
obj1.fun1();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
new Thread() {
@Override
public void run() {
try {
obj2.fun2();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();
}
}
不互斥說明不同對象的非靜態鎖不共用
Synchronized修飾靜態方法,是對該類對象加鎖,俗稱“類鎖”。
同樣, 這裏的對象加鎖並非是說執行該加鎖方法的時候整個類的所有(靜態)成員都不允許其他線程訪問了,
而是說該類內所有的加鎖的靜態方法共用這一把鎖, 一個加鎖靜態方法執行, 同類另一個加鎖靜態方法不能執行,要等持有鎖的線程釋放鎖
還是上面的程序, 兩個方法全是靜態, 都加鎖,:
兩個線程分別執行該類兩個對象的靜態加鎖方法, 預期互斥執行, 證明與對象無關
互斥執行, 說明該鎖由類中靜態方法共用
我們把一個方法寫成靜態, 一個不靜態, 都加鎖, 由兩個類調用同一個對象的兩個方法, 預期不互斥, 證明靜態與非靜態方法不共用鎖:
不互斥,說明靜態與非靜態方法不共用鎖
synchronized方法與synchronized代碼塊的區別
synchronized methods() {}
與 synchronized (this) {}
之間並沒有什麼區別。
只是前者便於閱讀理解,而後者可以更精確的控制衝突限制訪問區域(粒度更小),鎖的範圍沒有變,鎖住的時間變短了因而性能更好。
synchronized(非this對象)
上述都是使用synchronized(this)的格式來同步代碼塊,但JAVA還支持對"任意對象"作爲對象監視器來實現同步的功能。這個"任意對象"大多數是實例變量及方法的參數,使用格式爲synchronized(非this對象)。
其實同理,鎖住的不是當前實例對象,而是放入synchronized(非this對象)中的非this對象(與該非this對象的其他加鎖方法共用鎖),即對該非this對象進行加鎖。
總結:
- 靜態方法的鎖屬於類, 一個類中所有加鎖的靜態方法共用該鎖
- 非靜態方法的鎖屬於對象, 一個對象中所有加鎖的非靜態方法共用, 和靜態方法的鎖不同而互不相干
- 加鎖的方法的執行不會影響同一個類/對象中未加鎖的方法的執行(因爲其他方法沒有鎖呀)
有參考下文: