[英]Why does the synchronized lock another method?
我是java多線程的新手,我編寫了一些類來測試synced的功能。我有一些使用synced的方法:
public class ShareUtil {
private static Queue<Integer> queue = new LinkedList<Integer>();
public static synchronized void do1(){
System.out.println("do1");
sleep();
}
public static synchronized void do2(){
System.out.println("do2");
sleep();
}
private static void sleep(){
try {
Thread.sleep(1000*50000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
您可以看到有兩種使用同步的方法,並且我運行兩個線程分別使用這兩種方法。
class Run1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
ShareUtil.do1();
}
}
class Run2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
ShareUtil.do2();
}
}
public class DoMain {
public static void main(String[] args) {
ExecutorService pools = Executors.newCachedThreadPool();
for(int i=0;i<10;i++){
pools.execute(new Run1());
pools.execute(new Run2());
}
pools.shutdown();
}
}
但是,它只打印“ do1”而不打印“ do2”。我想知道為什么嗎?使用“ synchronized”鍵的方法使該方法只能同時使用一個線程,但是為什么要鎖定其他方法呢?
重要的鍵是synchronized
鎖對象,而不是方法。
根據https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
每個對象都有一個與之關聯的固有鎖。 按照約定,需要對對象的字段進行獨占且一致的訪問的線程必須在訪問對象之前先獲取對象的固有鎖,然后在完成對它們的鎖定后釋放固有鎖。 據稱,線程在獲取鎖和釋放鎖之間擁有內部鎖。 只要一個線程擁有一個內在鎖,其他任何線程都無法獲得相同的鎖。 另一個線程在嘗試獲取鎖時將阻塞。
因此, 當線程T1執行do1()時 , ShareUtil的類固有鎖定(您的方法是static
,所以這是與該類關聯的Class對象的固有鎖定 ) 被鎖定 ,除非T1釋放,否則其他線程都無法獲得此鎖定。它。
而且您調用的sleep()
方法不會釋放此鎖,而如果調用wait()
則會釋放此鎖,請檢查wait()和sleep()之間的區別 。 這就是為什么當另一個線程T2嘗試訪問do2()時,它必須等待T1的do1()完成(釋放內部鎖)的原因。
因為當您同步static
方法時,它會獲得對Class
對象的鎖定。 一旦線程在Class
對象上鎖定,其他任何線程都不能輸入同一類的另一個static
方法。
當您在具有鎖的線程上調用sleep()
時,其他線程都無法訪問其他靜態方法,因為該線程不會丟失鎖的所有權。
因此, sleep()
僅導致其中一個線程執行其方法。 您還可以得到有時do2
打印,但不do1
。
Run1()首先啟動,獲取對類ShareUtil的鎖定,其后是Run2(),直到Run1()釋放該鎖定為止,Run2()才被鎖定。 一旦Run2()獲得鎖,它將打印do2()。 如果方法是靜態的,則同步密鑰通過獲取對類的鎖定來確保只有一個線程訪問該方法;如果方法是實例,則通過“對象”來確保。
我更改代碼Thread.sleep(1000*50000);
到Thread.sleep(1000*2);
輸出結果是不規則的。
do2
do1
do1
do1
do1
do1
do1
do1
do1
do2
do2
do2
do2
do2
do2
do2
do2
do2
do1
我們可以看到這些線程正在等待ShareUtil.class的鎖,並在Thread.sleep
之后重新獲得該鎖,其中一個正在等待的線程將抓住該鎖並開始運行。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.