鎖定代碼塊等價於鎖定對象
首選看一下鎖定代碼塊的語法?
synchronized (對象)
{
// 代碼塊
}
上面的語法中的"對象",指的是實例對象,可以是this
,Class.clss
或者其他共享對象
.所以代碼塊鎖定的等價於對象鎖定.我們甚至還可以假設一下.把上面代碼的"對象"做成變量:
public void func1(Object lock) { // 這個方法沒有鎖定,鎖定的是裏面的代碼塊
synchronized (lock) {
System.out.println("方法開始");
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("方法結束");
}
}
那如果我們鎖住的不是lock
對象,而是func1
裏面的代碼,那無論傳入的lock
對象是什麼,這段代碼都不能併發執行了.這顯然是不可能的.我們看看輸出也再次證明了這個結論:
方法開始
方法開始
方法結束
方法結束
鎖定非靜態方法等價於鎖定對象
先拋出原因:
對象的非靜態 synchronized 方法被調用的時候,會先將對象鎖定,類似自動調用synchronized(this).
驗證:
假如我們一個進程先調用對象的非靜態 synchronized 方法,然後另一個進程調用 synchronized(this).
如果第一個進程沒有爲對象加鎖,第二個進程就能調用成功,然後兩者是並行的,結論不成立
反之,第二個進程無法獲得對象鎖,兩個進程就必須串行,結論成立
- 先定義共享對象
class TestSyn {
public synchronized void func1() { // 這個方法沒有鎖定,鎖定的是裏面的代碼塊
System.out.println("我是方法10");
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("我是方法11");
}
public void func2() {
synchronized (this)
{
System.out.println("我是方法20");
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("我是方法21");
}
}
}
2.然後定義兩個線程分別調用共享對象的不同方法
public class Singleton {
public static void main(String[] args) throws InterruptedException {
TestSyn testSyn = new TestSyn();
new Thread(new Runnable() {
@Override
public void run() {
testSyn.func1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
testSyn.func2();
}
}).start();
}
}
3.查看輸出
我是方法10
我是方法11
我是方法20
我是方法21
最後得出結論
程序串行執行,所以第二個人線程調用方法fun2的時候沒有得到this的鎖.說明this已經被鎖定.
引申: 同一個對象的兩個同步非靜態方法可以併發執行嗎?
答案:不行,因爲兩者都要獲得this鎖,屬於競爭關係
證明:
- 先定義同步對象
class TestSyn {
public synchronized void func1() { // 這個方法沒有鎖定,鎖定的是裏面的代碼塊
System.out.println("我是方法10");
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("我是方法11");
}
public synchronized void func2() {
System.out.println("我是方法20");
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("我是方法21");
}
}
- 然後定義兩個線程分別調用這兩個方法
public class Singleton {
public static void main(String[] args) throws InterruptedException {
TestSyn testSyn = new TestSyn();
new Thread(new Runnable() {
@Override
public void run() {
testSyn.func1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
testSyn.func2();
}
}).start();
}
}
- 查看輸出是串行執行.
我是方法10
我是方法11
我是方法20
我是方法21