日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

pool(三)——Timer

發布時間:2024/3/13 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 pool(三)——Timer 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?1.關于Timer的三個維度

首先是 {@link java.util.Timer},這個是最外層的類,其中包含了{@link java.util.TaskQueue},這個是存放{@link java.util.TimerTask}的隊列——a priority queue of TimerTasks。

第二層是 {@link java.util.TimerThread},這個是{@link java.util.Timer}在初始化的時候創建并啟動的一個線程,這個線程取任務并且執行。

/*** Creates a new timer whose associated thread has the specified name.* The associated thread does <i>not</i>* {@linkplain Thread#setDaemon run as a daemon}.** @param name the name of the associated thread* @throws NullPointerException if {@code name} is null* @since 1.5*/public Timer(String name) {thread.setName(name);thread.start();}

2.TimerThread

Thread的子類,在run方法中循環取任務。

public void run() {try {mainLoop();} finally {// Someone killed this Thread, behave as if Timer cancelledsynchronized(queue) {newTasksMayBeScheduled = false;queue.clear(); // Eliminate obsolete references}}} /*** The main timer loop. (See class comment.)*/private void mainLoop() {while (true) {try {TimerTask task;boolean taskFired;synchronized(queue) {// Wait for queue to become non-emptywhile (queue.isEmpty() && newTasksMayBeScheduled)queue.wait();if (queue.isEmpty())break; // Queue is empty and will forever remain; die// Queue nonempty; look at first evt and do the right thinglong currentTime, executionTime;task = queue.getMin();synchronized(task.lock) {if (task.state == TimerTask.CANCELLED) {queue.removeMin();continue; // No action required, poll queue again}currentTime = System.currentTimeMillis();executionTime = task.nextExecutionTime;if (taskFired = (executionTime<=currentTime)) {if (task.period == 0) { // Non-repeating, removequeue.removeMin();task.state = TimerTask.EXECUTED;} else { // Repeating task, reschedulequeue.rescheduleMin(task.period<0 ? currentTime - task.period: executionTime + task.period);}}}if (!taskFired) // Task hasn't yet fired; waitqueue.wait(executionTime - currentTime);}if (taskFired) // Task fired; run it, holding no lockstask.run();} catch(InterruptedException e) {}}}

3.task的創建——schedule方法

public void schedule(TimerTask task, long delay, long period) {if (delay < 0)throw new IllegalArgumentException("Negative delay.");if (period <= 0)throw new IllegalArgumentException("Non-positive period.");sched(task, System.currentTimeMillis()+delay, -period);} /*** Schedule the specified timer task for execution at the specified* time with the specified period, in milliseconds. If period is* positive, the task is scheduled for repeated execution; if period is* zero, the task is scheduled for one-time execution. Time is specified* in Date.getTime() format. This method checks timer state, task state,* and initial execution time, but not period.** @throws IllegalArgumentException if <tt>time</tt> is negative.* @throws IllegalStateException if task was already scheduled or* cancelled, timer was cancelled, or timer thread terminated.* @throws NullPointerException if {@code task} is null*/private void sched(TimerTask task, long time, long period) {if (time < 0)throw new IllegalArgumentException("Illegal execution time.");// Constrain value of period sufficiently to prevent numeric// overflow while still being effectively infinitely large.if (Math.abs(period) > (Long.MAX_VALUE >> 1))period >>= 1;synchronized(queue) {if (!thread.newTasksMayBeScheduled)throw new IllegalStateException("Timer already cancelled.");synchronized(task.lock) {if (task.state != TimerTask.VIRGIN)throw new IllegalStateException("Task already scheduled or cancelled");task.nextExecutionTime = time;task.period = period;task.state = TimerTask.SCHEDULED;}queue.add(task);if (queue.getMin() == task)queue.notify();}}

1.兩重鎖,先鎖隊列queue,再鎖task,task中有一個Object對象作為鎖
2.設置TimerTask的下次執行時間
{@link java.util.TimerTask#nextExecutionTime} = System.currentTimeMillis()+delay
3.將任務添加到隊列中
{@link java.util.Timer#queue}
4.當前任務如果是隊列的一個任務,就執行
task == {@link java.util.TaskQueue#getMin},調用queue的notify方法。如果不是,說明前面還有等待執行的task,只入隊列,不用調用notify方法。
5.{@link java.util.TimerThread#mainLoop}
{@link java.util.TimerThread}會在{@link java.util.Timer}
構造的時候啟動,進而調用mainLoop方法。
最開始queue是空的,所以queue.await(),當前線程掛起,當Timer中添加TimerTask任務時,
就會調用queue.notify()方法喚醒mainLoop線程。
?

4.根據優先級對堆進行重排序

1.TimerTask的入堆(queue)操作

delay時間設置的很長,就是為了讓任務不執行,看看入隊列的比較操作,period這里完全用作標志位,在debug的時候作為標記區分不同的Task,看看排序狀況。
這里以3個為例,第一個入隊列,index是1,第二個入隊列,index是2,2>>1=1,然后拿queue[2]和queue[1]比較下次執行時間,queue[2]比queue[1]早,所以交換順序。
第三個入隊列,index是3,3>>1=1,和第一個比,queue[3]比queue[1]要早,所以交換順序,所以現在queue[1]最早執行,queue[2]和queue[3]的順序沒有考慮。每次入隊列的重排序操作在 {@link java.util.TaskQueue#fixUp} 方法中進行

/*** Establishes the heap invariant (described above) assuming the heap* satisfies the invariant except possibly for the leaf-node indexed by k* (which may have a nextExecutionTime less than its parent's).** This method functions by "promoting" queue[k] up the hierarchy* (by swapping it with its parent) repeatedly until queue[k]'s* nextExecutionTime is greater than or equal to that of its parent.*/private void fixUp(int k) {while (k > 1) {int j = k >> 1;if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)break;TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;k = j;}}

2.mainLoop執行操作:

每次取queue的第一個task,如果該task還沒到執行時間,就等待對應的時間queue.wait(executionTime - currentTime)。

if (!taskFired) // Task hasn't yet fired; waitqueue.wait(executionTime - currentTime);

如果這期間又來了一個優先級更高(執行順序更靠前)的task,入隊列時調用fixUp把當前task排到隊列頭(優先級更高),然后notify這個queue打斷這個wait,重新去取優先級更高的task。

/*** Adds a new task to the priority queue.*/void add(TimerTask task) {// Grow backing store if necessaryif (size + 1 == queue.length)queue = Arrays.copyOf(queue, 2*queue.length);queue[++size] = task;fixUp(size);}

如果到了執行時間(wait結束),在下次循環的時候,就執行該task。

如果是非重復任務,調用removeMin移除當前任務,在removeMin中fixDown,進行堆重排序。

如果是重復任務的話,還要調用rescheduleMin設置下次執行的時間,在rescheduleMin中調用fixDown,進行堆重排序。

3.{@link java.util.TaskQueue#fixDown}

/*** Establishes the heap invariant (described above) in the subtree* rooted at k, which is assumed to satisfy the heap invariant except* possibly for node k itself (which may have a nextExecutionTime greater* than its children's).** This method functions by "demoting" queue[k] down the hierarchy* (by swapping it with its smaller child) repeatedly until queue[k]'s* nextExecutionTime is less than or equal to those of its children.*/private void fixDown(int k) {int j;while ((j = k << 1) <= size && j > 0) {if (j < size &&queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)j++; // j indexes smallest kidif (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)break;TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;k = j;}}

對剩下的Task進行重新排序,把下次執行時間最小的轉移到第一個任務的位置。

測試用例:

public static void test1() {timer.schedule(new TimerTask() {@Override public void run() {System.out.println("Time's up 1!---" + new Date().toString());// SleepUtil.sleep(30000);}}, 2000 * 1000, 11 * 1000);timer.schedule(new TimerTask() {@Override public void run() {System.out.println("Time's up 2!---" + new Date().toString());// SleepUtil.sleep(30000);}}, 1500 * 1000, 22 * 1000);timer.schedule(new TimerTask() {@Override public void run() {System.out.println("Time's up 3!---" + new Date().toString());// SleepUtil.sleep(30000);}}, 5 * 1000, 333333 * 1000);}

5.TimerTask的執行順序

可以得知Timer內部是單線程執行task的,一個timer對象只會啟用一個TimerThread的。

當一個timer執行多個任務時,如果一個任務執行的時間過長,后面任務執行的時間可能就不是你預期執行的時間了,因為一個任務執行完了才會執行下個任務。

測試用例:

public static void test3() {timer.schedule(new TimerTask() {@Override public void run() {System.out.println("Time's up 1!---" + new Date().toString());SleepUtil.sleep(0);}}, 0, 2 * 1000);timer.schedule(new TimerTask() {@Override public void run() {System.out.println("Time's up 2!---" + new Date().toString());SleepUtil.sleep(5000);}}, 0, 2 * 1000);// EvictionTimer.schedule(evictor, delay, delay);}

TimerTask執行時間過長,超過了period,執行5s,period是2s,這樣period相當于失效了。因為下次執行的時間是這樣計算的,
{@link java.util.TimerTask#nextExecutionTime} = System.currentTimeMillis()+delay
所以,當本次任務執行結束(過了超過5s),到下次任務取出來判斷的執行時間的時候,肯定已經超過了原本應該執行的時間。

根據mainLoop中的邏輯,當判斷執行時間比當前時間要早的話,直接執行本次任務。
?

總結

以上是生活随笔為你收集整理的pool(三)——Timer的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。