Java併發程式設計 延時任務佇列的實現原理

2021-09-16 12:44:54 字數 2538 閱讀 2837

優先順序佇列delayedworkqueue

delayedworkqueue用來存放將要執行的任務,其資料結構為有序二叉堆。

有序二叉堆的特點:

所有根結點必定不大於其兩個葉子節點

任意結點的子節點的索引位置是其本身索引位置乘2後+1

任意結點的父節點的索引位置是該結點的索引位置-1後除2並向下取整

當新新增元素時,加入到陣列的尾部,後面我們結合**分析新增過程delayedworkqueue按照任務超時時間公升序排序,原因是為了將即將要執行的任務放在盡量靠前的位置。下面分析新增操作:

public

boolean

offer

(runnable x)

else

if(queue[0]

== e)

}finally

return

true

;}

在呼叫此方法之前已經把任務封裝為runnablescheduledfuture型別,說白了其內部就是多了乙個執行時間,並且重寫了compareto方法。繼續看siftup()的實現,引數i為陣列的下標。

private

void

siftup

(int k, runnablescheduledfuture<

?> key)

queue[k]

= key;

setindex

(key, k)

;}

找到新元素的父節點,然後和父元素進行比較,如果新元素大於大於父節點(compareto)直接返回,否則和父元素進行交換。獲取元素有三種方式,poll()、take()、poll(long timeout, timeunit unit),分別為立即獲取、等待獲取、超時等待獲取。這裡主要分析等待獲取take方法。

public runnablescheduledfuture<

?>

take()

throws interruptedexception

finally}}

}}finally

}

注意一點leader變數表示正在獲取頭元素的執行緒,在**[1]處的判斷是什麼意思?假設佇列現在是空的,這是執行緒a進入,發現first為null會呼叫await方法,進入等待佇列。這是他會釋放鎖,有任務加入。就在此時執行緒b和執行緒a同時競爭鎖,但是執行緒b獲得了鎖,在**[2]處等待一定時間同時釋放鎖,但是執行緒a不一定會被喚醒,除非在b睡眠的時候有任務加入。很巧,此時執行緒a競爭到了鎖,來到[1]處,leader不為null,再次進入await。直到執行緒b執行完畢,呼叫了signal方法。

如果任務過期或者到達執行時間返回任務,並且重新組織二叉排序堆

private runnablescheduledfuture<

?>

finishpoll

(runnablescheduledfuture<

?> f)

private

void

siftdown

(int k, runnablescheduledfuture<

?> key)

queue[k]

= key;

// 將key賦值剛給右節點

setindex

(key, k)

;}

陣列的大小減1,獲取最後乙個節點同時置位null,呼叫siftdown方法,入參為0和最後乙個節點。

scheduledthreadpoolexecutor

scheduledthreadpoolexecutor 計畫任務執行緒池,這裡就不介紹他的具體使用方式了。其內部有兩個重要的內部類,delayedworkqueue和scheduledfuturetask。先看一下schedule方法。

public scheduledfuture<

?>

schedule

(runnable command,

long delay, timeunit unit)

schedule方法的作用是將定時任務封裝為runnablescheduledfuture型別,並新增值阻塞佇列中。至於何時呼叫,回想執行緒池中分析過,gettask方法:

private runnable gettask()

catch

(interruptedexception retry)

}

執行poll或者take時會阻塞到任務的執行時間。

總結:

計畫任務的延時和阻塞功能是在延時佇列中實現。

文中沒有詳細的描述scheduledfuturetask類,該類是對任務的封裝,並且scheduleatfixedrate的也是通過該類實現的,當任務執行完成之後,會再次新建乙個任務,加入到延時佇列中,這樣就可以重複的執行任務了。

系統的定時任務和延時任務

注 當任務有輸出時,輸出會以郵件的形式傳送給at任務的發起者。步驟 開啟postfix服務 命令 內部命令 1.輸入數字是檢視指定郵件的具體資訊 2.headers是檢視郵件列表 3.help檢視內部命令幫助 4.q是退出檢視郵件 命令 注 如果不寫username,預設在當前使用者執行命令 步驟 ...

Linux中的延時任務以及定時任務

root localhost at 23 37 設定任務執行時間 at rm fr mnt 任務執行動作 at ctrl d 用ctrl d發起任務 root localhost at now 1min 延時1分鐘 at rm fr mnt at 命令 注釋at l 檢視任務列表 at c 檢視任務...

Linux下的定時任務與延時任務

1 延時任務發起命令 at at 命令可以指定某一任務在將來的特定時間執行。該任務會在與shell會話斷開連線的情況下執行,用at命令將任務設定在一兩分鐘後執行時可以安全登出 at 命令必須指定任務應執行的時間。該指定可以是具體時間和日期,也可以是當前時間的相對時間 在鍵入 at 命令列之後 按 e...