Java執行緒中的 重入 詳解
阿新 • • 發佈:2019-01-24
當某個執行緒請求一個由其他執行緒持有的鎖時,發出請求的執行緒就會阻塞。然而,由於內建鎖是可重入的,因此如果某個執行緒試圖獲得一個已經由它自己持有的鎖,那麼這個請求就會成功。
“重入”意味著獲取鎖的操作的粒度是“執行緒”,而不是“呼叫”。重入的一種實現方法是,為每個鎖關聯一個獲取計數值和一個所有者執行緒。當計數值為0時,這個鎖就被認為是沒有被任何執行緒持有。
當執行緒請求一個未被持有的鎖時,JVM將記下鎖的持有者,並且將獲取計數值置位1。如果同一個執行緒再次獲取這個鎖,計數值將遞增,而當執行緒退出同步程式碼塊時,計數器將會相應地遞減。當計數值為0時,這個鎖將被釋放。
重入進一步提升了加鎖行為的封裝性,因此簡化了面向物件併發程式碼的開發。在以下程式碼中,子類改寫了父類的synchronized方法,然後呼叫父類中的方法,此時如果沒有可重入的鎖,那麼這段程式碼將產生死鎖。由於Widget和LoggingWidget中doSomething方法都是synchronized方法,因此每個doSomething方法在執行前都會獲取Widget上的鎖,然而,如果內建鎖不是可重入的,那麼在呼叫super.doSomething時將無法獲得Widget上的鎖,因為這個鎖已經被持有,從而執行緒將永遠停頓下去,等待一個永遠也無法獲得的鎖。重入則避免了這種死鎖情況的發生。
package com.ntp.qzpTest;
public class Widget {
public synchronized void doSomething(){
System.out.println("我是父類中的doSomething !!");
}
}
package com.ntp.qzpTest; public class LoggingWidget extends Widget{ public synchronized void doSomething(){ System.out.println("我是子類中的doSomething !!"); super.doSomething(); } }