java多執行緒3:關鍵字synchronized取得的鎖都是物件鎖,而不是把一段程式碼或者方法(函式)當作鎖
阿新 • • 發佈:2018-12-20
java多執行緒3:關鍵字synchronized取得的鎖都是物件鎖,而不是把一段程式碼或者方法(函式)當作鎖
a.當多個執行緒訪問同一個物件的時候,哪個執行緒先執行帶synchronized關鍵字的方法,哪個執行緒就該方法所屬物件的鎖Lock,那麼其他物件就智慧呈等待狀態。但是如果多個執行緒訪問多個物件的話,JVM就回創建出多個鎖。
同步的單詞是:synchronized,非同步的單詞是:asynchronized.
package multiThread.synchro; public class OneNumber { int num = 0; public void receiveUserName(String userName) { if (userName.equals("a")) { num = 100; } else { num = 200; } System.out.println("userName:" + userName + " 數字是:" + num); } }
package multiThread.synchro;
public class AThread extends Thread {
private OneNumber oneNumber;
public AThread(OneNumber oneNumber) {
this.oneNumber = oneNumber;
}
public void run() {
oneNumber.receiveUserName("a");
}
}
package multiThread.synchro; public class BThread extends Thread { private OneNumber oneNumber; public BThread(OneNumber oneNumber) { this.oneNumber = oneNumber; } public void run() { oneNumber.receiveUserName("b"); } }
package multiThread.synchro; public class Main { public static void main(String[] args) { OneNumber oneNumber = new OneNumber(); OneNumber oneNumber2=new OneNumber(); AThread aThread = new AThread(oneNumber); BThread bThread = new BThread(oneNumber2); aThread.start(); bThread.start(); } }
從上邊看出,我們的類OneNumber中沒有加鎖,同時在Main類中,使用了兩個不同的OneNumber物件。
所以測試結果控制檯列印如下:
上邊所示例子是兩個執行緒分別訪問同一個類的兩個不同例項的相同名稱的同步方法,效果確實以非同步的方式執行的。這裡由於建立了兩個業務物件,在系統中產生出兩個鎖,所以執行結果也是非同步的。上邊加鎖和不加鎖都是非同步進行。
b.對OneNumber類進行修改,把num修改為區域性變數,同時下邊添加了休眠方法後再列印內容
package multiThread.synchro;
public class OneNumber {
public void receiveUserName(String userName) {
int num = 0;
if (userName.equals("a")) {
num = 100;
} else {
num = 200;
}
System.out.println("userName:" + userName + " 數字是:" + num);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(userName + "end");
}
}
同時修改Main類,修改為使用同一個OneNumber物件:
package multiThread.synchro;
public class Main {
public static void main(String[] args) {
OneNumber oneNumber = new OneNumber();
AThread aThread = new AThread(oneNumber);
BThread bThread = new BThread(oneNumber);
aThread.start();
bThread.start();
}
}
控制檯:
通過上邊例子,我們這個時候是訪問同一個類中資料,區域性變數,沒有出現訪問異常,只是我們訪問也是同時進入那個方法,沒有先後順序,但是沒有打亂我們資料,也就是資料沒有共享,但是訪問順序混亂
c.那麼如果我們在我們訪問的同一個物件中同一個方法新增同步鎖,那麼就可以實現順序訪問了。
package multiThread.synchro;
public class OneNumber {
synchronized public void receiveUserName(String userName) {
int num = 0;
if (userName.equals("a")) {
num = 100;
} else {
num = 200;
}
System.out.println("userName:" + userName + " 數字是:" + num);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(userName + "end");
}
}
其他程式碼不變,控制檯:
注意:對於訪問同一個物件中的同一個方法,要是這個方法使用關鍵字synchronized宣告的方法,呼叫這個方法的時候,一定是排隊進行的。
補充:A執行緒先持有物件的Lock鎖,B執行緒可以以非同步的方式呼叫object物件中的非synchronized型別的方法。
A執行緒先持有object物件的Lock鎖,B執行緒如果在這個時候,呼叫object物件中的sychronized型別方法則需等待,也就是同步。