JDK中的併發框架提供的另一個優秀機制是鎖獲取超時的支持,當大量線程對某一鎖競爭時可能致使某些線程在很長一段時間都獲取不了鎖,在某些場景下可能但願若是線程在一段時間內不能成功獲取鎖就取消對該鎖的等待以提升性能,這時就須要用到超時機制。在JDK1.5以前並無對此支持,當時的併發控制職能經過JVM內置的synchronized關鍵詞實現鎖,但對一些特殊要求卻力不從心,例如超時取消控制。JDK1.5開始引入併發工具完美解決了此問題,JDK對併發線程開始提供超時的支持。java
爲了更精確地保證時間間隔統計的準確性,實現時使用了System.nanoTime()更爲精確的方法,它能精確到納秒級別。超時機制的思想就是在不斷進行鎖競爭的同時記錄競爭的時間,一旦時間段超過指定的時間則中止輪詢直接返回,返回前對等待隊列中對應節點進行取消操做。往下看實現的邏輯:node
if(嘗試獲取鎖失敗) {
long lastTime = System.nanoTime();
建立node
使用CAS方式把node插入到隊列尾部
while(true){
if(嘗試獲取鎖成功 而且 node的前驅節點爲頭節點){
把當前節點設置爲頭節點
跳出循環
}else{
if (nanosTimeout <= 0){
取消等待隊列中此節點
跳出循環
}
使用CAS方式修改node前驅節點的waitStatus標識爲signal if(修改爲功) if(nanosTimeout > spinForTimeoutThreshold) 阻塞當前線程nanosTimeout納秒 long now = System.nanoTime();
nanosTimeout -= now - lastTime;
lastTime = now;
}
}
}複製代碼
上面正在鎖的獲取邏輯中添加超時處理,核心邏輯是不斷循環減去處理的時間消耗,一旦小於0就取消節點並跳出循環,其中有兩點必需要注意,一個是真正的阻塞時間應該是扣除了競爭入隊的時間後剩餘的時間,保證阻塞事件的準確性,咱們能夠看到每次循環都會減去相應的處理時間;另一個是關於spinForTimeoutThreshold變量閥值,它是決定使用自旋方式消耗時間仍是使用系統阻塞方式消耗時間的分割線,JDK併發工具包做者經過測試將默認值設置爲1000ns,即若是在成功插入等待隊列後剩餘時間大於1000ns則調用系統底層阻塞,不然不調用系統底層,取而代之的是僅僅讓之在Java應用層不斷循環消耗時間,屬於優化的措施。併發
至此,JDK實如今獲取鎖的過程當中提供了超時機制,超時的支持讓Java在併發方面提供了更完善的機制,更多的併發策略知足開發者更多需求。框架
歡迎關注
工具