亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java定時(shí)器Timer的源碼分析

 更新時(shí)間:2022年11月02日 11:09:42   作者:UnicornLien  
通過源碼分析,我們可以更深入的了解其底層原理。本文將通過Timer的源碼,帶大家深入了解Java?Timer的使用,感興趣的小伙伴可以了解一下

通過源碼分析,我們可以更深入的了解其底層原理。

對(duì)于JDK自帶的定時(shí)器,主要涉及TimerTask類、Timer類、TimerQueue類、TimerThread類,其中TimerQueue和TimerThread類與Timer類位于同一個(gè)類文件,由Timer內(nèi)部調(diào)用。

先畫上一張圖,描述一下Timer的大致模型,Timer的模型很容易理解,即任務(wù)加入到任務(wù)隊(duì)列中,由任務(wù)處理線程循環(huán)從任務(wù)隊(duì)列取出任務(wù)執(zhí)行:

一、TimerTask

TimerTask是一個(gè)任務(wù)抽象類,實(shí)現(xiàn)了Runnable接口,是可被線程執(zhí)行的。

1. 任務(wù)狀態(tài)

在TimerTask中定義了關(guān)于任務(wù)狀態(tài)的常量字段:

//	未調(diào)度狀態(tài)
static final int VIRGIN = 0;
//	任務(wù)已調(diào)度,但未執(zhí)行
static final int SCHEDULED   = 1;
//	若是一次性任務(wù)表示已執(zhí)行;可重復(fù)執(zhí)行任務(wù),該狀態(tài)無效
static final int EXECUTED    = 2;
//	任務(wù)被取消
static final int CANCELLED   = 3;

當(dāng)一個(gè)TimerTask對(duì)象創(chuàng)建后,其初始狀態(tài)為VIRGIN;

當(dāng)調(diào)用Timer的schedule方法調(diào)度了此TimerTask對(duì)象后,其狀態(tài)變更為SCHEDULED;

如果TimerTask是一次性任務(wù),此任務(wù)執(zhí)行后,狀態(tài)將變?yōu)镋XECUTED,可重復(fù)執(zhí)行任務(wù)執(zhí)行后狀態(tài)不變;

當(dāng)中途調(diào)用了TimerTask.cancel方法,該任務(wù)的狀態(tài)將變?yōu)镃ANCELLED。

2. 任務(wù)屬性說明

TimerTask中,有如下成員變量:

//	用于加鎖控制多線程修改TimerTask內(nèi)部狀態(tài)
final Object lock = new Object();

//	任務(wù)狀態(tài),初始狀態(tài)為待未調(diào)度狀態(tài)
int state = VIRGIN;

//	任務(wù)的下一次執(zhí)行時(shí)間點(diǎn)
long nextExecutionTime;

//  任務(wù)執(zhí)行的時(shí)間間隔。正數(shù)表示固定速率;負(fù)數(shù)表示固定時(shí)延;0表示只執(zhí)行一次
long period = 0;

3. 任務(wù)方法說明

TimerTask中有三個(gè)方法:

  • run:實(shí)現(xiàn)了Runnable接口,創(chuàng)建TimerTask需要重寫此方法,編寫任務(wù)執(zhí)行代碼
  • cancel:取消任務(wù)
  • scheduledExecutionTime:計(jì)算執(zhí)行時(shí)間點(diǎn)

3.1. Cancel方法

cancel方法的實(shí)現(xiàn)代碼:

public boolean cancel() {
    synchronized(lock) {
        boolean result = (state == SCHEDULED);
        state = CANCELLED;
        return result;
    }
}

在cancel方法內(nèi),使用synchronized加鎖,這是因?yàn)門imer內(nèi)部的線程會(huì)對(duì)TimerTask狀態(tài)進(jìn)行修改,而調(diào)用cancel方法一般會(huì)是另外一個(gè)線程。

為了避免線程同步問題,cancel在修改狀態(tài)前進(jìn)行了加鎖操作。

調(diào)用cancel方法將會(huì)把任務(wù)狀態(tài)變更為CANCELLED狀態(tài),即任務(wù)取消狀態(tài),并返回一個(gè)布爾值,該布爾值表示此任務(wù)之前是否已是SCHEDULED 已調(diào)度狀態(tài)。

3.2. scheduledExecutionTime方法

scheduledExecutionTime方法實(shí)現(xiàn):

public long scheduledExecutionTime() {
    synchronized(lock) {
        return (period < 0 ? nextExecutionTime + period
                           : nextExecutionTime - period);
    }
}

該方法返回此任務(wù)的下次執(zhí)行時(shí)間點(diǎn)。

二、Timer

分析Timer源代碼,Timer在內(nèi)部持有了兩個(gè)成員變量:

private final TaskQueue queue = new TaskQueue();

private final TimerThread thread = new TimerThread(queue);

TaskQueue是任務(wù)隊(duì)列,TimerThread是任務(wù)處理線程。

1. sched方法

無論是使用schedule還是scheduleAtFixedRate方法來調(diào)度任務(wù),Timer內(nèi)部最后都是調(diào)用sched方法進(jìn)行處理。

public void schedule(TimerTask task, Date time) {
    sched(task, time.getTime(), 0);	//	一次性任務(wù),period為0
}

public void schedule(TimerTask task, long delay) {
    ...
    sched(task, System.currentTimeMillis()+delay, 0);	//	一次性任務(wù),period為0
}

public void schedule(TimerTask task, long delay, long period) {
    ...
    sched(task, System.currentTimeMillis()+delay, -period);	//	固定延時(shí)模式,-period
}

public void schedule(TimerTask task, Date firstTime, long period) {
    ...
    sched(task, firstTime.getTime(), -period);	//	固定延時(shí)模式,-period
}

public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    ...
    sched(task, System.currentTimeMillis()+delay, period);	//	固定速率模式,period為正
}

public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
    ...
    sched(task, firstTime.getTime(), period);	//	固定速率模式,period為正
}

sched方法核心代碼:

private void sched(TimerTask task, long time, long period) {
   ...

    //	加鎖,避免外部其他線程同時(shí)調(diào)用cancel,同時(shí)訪問queue產(chǎn)生線程同步問題
    synchronized(queue) {

        //	如果線程已終止,拋出異常
        if (!thread.newTasksMayBeScheduled)
            throw new IllegalStateException("Timer already cancelled.");

        //	加鎖,避免多線程訪問同一個(gè)任務(wù)產(chǎn)生線程同步問題
        synchronized(task.lock) {
            
            //	task的狀態(tài)必須為VIRGIN,否則認(rèn)為已經(jīng)加入調(diào)度或者已經(jīng)取消了,避免重復(fù)的調(diào)度
            if (task.state != TimerTask.VIRGIN)
                throw new IllegalStateException(
                    "Task already scheduled or cancelled");
            
            //	設(shè)置下次執(zhí)行時(shí)間點(diǎn)
            task.nextExecutionTime = time;
            //	設(shè)置時(shí)間間隔
            task.period = period;
            //	任務(wù)狀態(tài)變更為已調(diào)度
            task.state = TimerTask.SCHEDULED;
        }

        //	將任務(wù)添加到隊(duì)列中
        queue.add(task);
        
    	//	如果此任務(wù)是最近的任務(wù),喚醒線程
        if (queue.getMin() == task)
            queue.notify();
    }
}

2. cancel方法

cancel方法一般是由外部其他線程調(diào)用,而Timer內(nèi)部的線程也會(huì)對(duì)任務(wù)隊(duì)列進(jìn)行操作,因此加鎖。

public void cancel() {
    synchronized(queue) {
        //	修改線程的循環(huán)執(zhí)行標(biāo)志,令線程能夠終止
        thread.newTasksMayBeScheduled = false;
        //	清空任務(wù)隊(duì)列
        queue.clear();
        //	喚醒線程
        queue.notify();
    }
}

3. purge方法

當(dāng)通過TimerTask.cancel將任務(wù)取消后,Timer的任務(wù)隊(duì)列還引用著此任務(wù),Timer只有到了要執(zhí)行時(shí)才會(huì)移除,其他時(shí)候并不會(huì)自動(dòng)將此任務(wù)移除,需要調(diào)用purge方法進(jìn)行清理。

public int purge() {
     int result = 0;

     synchronized(queue) {
         
         //	遍歷隊(duì)列,將CANCELLED狀態(tài)的任務(wù)從任務(wù)隊(duì)列中移除
         for (int i = queue.size(); i > 0; i--) {
             if (queue.get(i).state == TimerTask.CANCELLED) {
                 queue.quickRemove(i);
                 result++;
             }
         }

         //	如果移除任務(wù)數(shù)不為0,觸發(fā)重新排序
         if (result != 0)
             queue.heapify();
     }

    //	返回移除任務(wù)數(shù)
     return result;
 }

三、TaskQueue

TaskQueue是Timer類文件中封裝的一個(gè)隊(duì)列數(shù)據(jù)結(jié)構(gòu),內(nèi)部默認(rèn)是一個(gè)長(zhǎng)度128的TimerTask數(shù)組,當(dāng)任務(wù)加入時(shí),檢測(cè)到數(shù)組將滿將會(huì)自動(dòng)擴(kuò)容1倍,并對(duì)數(shù)組元素根據(jù)下次執(zhí)行時(shí)間nextExecutionTime按時(shí)間從近到遠(yuǎn)進(jìn)行排序。

void add(TimerTask task) {
    // 檢測(cè)數(shù)組長(zhǎng)度,若不夠則進(jìn)行擴(kuò)容
    if (size + 1 == queue.length)
        queue = Arrays.copyOf(queue, 2*queue.length);

	//	任務(wù)入隊(duì)
    queue[++size] = task;

	//	排序
    fixUp(size);
}

fixUp方法實(shí)現(xiàn):

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;
    }
}

TaskQueue中除了fixUp方法外還有一個(gè)fixDown方法,這兩個(gè)其實(shí)就是堆排序算法,在算法專題中再進(jìn)行詳細(xì)介紹,只要記住他們的任務(wù)就是按時(shí)間從近到遠(yuǎn)進(jìn)行排序,最近的任務(wù)排在隊(duì)首即可。

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 kid
        if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
            break;
        TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
        k = j;
    }
}

void heapify() {
    for (int i = size/2; i >= 1; i--)
        fixDown(i);
}

四、TimerThread

TimerThread的核心代碼位于mainLoop方法:

private void mainLoop() {
    
    //	死循環(huán),從隊(duì)列取任務(wù)執(zhí)行
    while (true) {
        try {
            TimerTask task;
            boolean taskFired;
            
            //	對(duì)任務(wù)隊(duì)列加鎖
            synchronized(queue) {
                
                //	如果隊(duì)列中沒有任務(wù),則進(jìn)入等待,newTasksMayBeScheduled是線程運(yùn)行標(biāo)志位,為false時(shí)將退出循環(huán)
                while (queue.isEmpty() && newTasksMayBeScheduled)
                    queue.wait();
                
                //	如果任務(wù)隊(duì)列是空的還執(zhí)行到這一步,說明newTasksMayBeScheduled為false,退出循環(huán)
                if (queue.isEmpty())
                    break; 

                long currentTime, executionTime;
                
                //	從隊(duì)列取得最近的任務(wù)
                task = queue.getMin();
                
                //	加鎖
                synchronized(task.lock) {
                    
                    //	如果任務(wù)狀態(tài)是已取消,則移除該任務(wù),重新循環(huán)取任務(wù)
                    if (task.state == TimerTask.CANCELLED) {
                        queue.removeMin();
                        continue; 
                    }
                    
                    //	當(dāng)前時(shí)間
                    currentTime = System.currentTimeMillis();
                    //	任務(wù)的執(zhí)行時(shí)間點(diǎn)
                    executionTime = task.nextExecutionTime;
                    
                    //	如果執(zhí)行時(shí)間點(diǎn)早于或等于當(dāng)前時(shí)間,即過期/時(shí)間到了,則觸發(fā)任務(wù)執(zhí)行
                    if (taskFired = (executionTime<=currentTime)) {

                        //	如果任務(wù)period=0,即一次性任務(wù)
                        if (task.period == 0) {

                            //	從隊(duì)列移除一次性任務(wù)
                            queue.removeMin();


                            //	任務(wù)狀態(tài)變更為已執(zhí)行
                            task.state = TimerTask.EXECUTED;

                        } else {

                            //	可重復(fù)執(zhí)行任務(wù),重新進(jìn)行調(diào)度,period<0是固定時(shí)延,period>0是固定速率
                            queue.rescheduleMin(
                              task.period<0 ? currentTime   - task.period	//	計(jì)算下次執(zhí)行時(shí)間
                                            : executionTime + task.period);
                        }
                    }
                }
                
                // taskFired為false即任務(wù)尚未到執(zhí)行時(shí)間點(diǎn),進(jìn)行等待,等待時(shí)間是 執(zhí)行時(shí)間點(diǎn) - 當(dāng)前時(shí)間點(diǎn)
                if (!taskFired)
                    queue.wait(executionTime - currentTime);
            }

            //	taskFired為true表示已觸發(fā),執(zhí)行任務(wù)
            if (taskFired)  
                task.run();
        } catch(InterruptedException e) {
        }
    }
}

以上就是Java定時(shí)器Timer的源碼分析的詳細(xì)內(nèi)容,更多關(guān)于Java Timer的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java對(duì)象序列化操作實(shí)例分析

    java對(duì)象序列化操作實(shí)例分析

    這篇文章主要介紹了java對(duì)象序列化操作,結(jié)合實(shí)例形式分析了java對(duì)象序列化操作相關(guān)實(shí)現(xiàn)步驟與操作注意事項(xiàng),需要的朋友可以參考下
    2019-11-11
  • springboot+maven多環(huán)境動(dòng)態(tài)配置及編譯失敗的解決方案(步驟詳解)

    springboot+maven多環(huán)境動(dòng)態(tài)配置及編譯失敗的解決方案(步驟詳解)

    這篇文章主要介紹了springboot+maven多環(huán)境動(dòng)態(tài)配置及編譯失敗的解決方案,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • java實(shí)現(xiàn)文件重命名功能

    java實(shí)現(xiàn)文件重命名功能

    這篇文章主要介紹了java實(shí)現(xiàn)文件重命名功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Spring中最常用的注解之一@Autowired詳解

    Spring中最常用的注解之一@Autowired詳解

    本文講解了Spring中最常用的注解之一@Autowired, 平時(shí)我們可能都是使用屬性注入的,但是后續(xù)建議大家慢慢改變習(xí)慣,使用構(gòu)造器注入。同時(shí)也講解了這個(gè)注解背后的實(shí)現(xiàn)原理,需要的朋友可以參考下
    2023-01-01
  • 數(shù)據(jù)庫(kù)基本操作語(yǔ)法歸納總結(jié)

    數(shù)據(jù)庫(kù)基本操作語(yǔ)法歸納總結(jié)

    本篇文章主要介紹了數(shù)據(jù)庫(kù)的一些常用方法及一些基本操作,需要的朋友可以參考下
    2017-04-04
  • Java實(shí)現(xiàn)簡(jiǎn)單井字棋小游戲代碼實(shí)例

    Java實(shí)現(xiàn)簡(jiǎn)單井字棋小游戲代碼實(shí)例

    這篇文章主要介紹了Java實(shí)現(xiàn)簡(jiǎn)單井字棋小游戲代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)

    SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)

    這篇文章主要介紹了如何使用SpringBoot整合Quartz,并將定時(shí)任務(wù)寫入庫(kù)中(持久化存儲(chǔ)),還可以任意對(duì)定時(shí)任務(wù)進(jìn)行如刪除、暫停、恢復(fù)等操作,需要的可以了解下
    2023-09-09
  • Javaweb EL自定義函數(shù)開發(fā)及代碼實(shí)例

    Javaweb EL自定義函數(shù)開發(fā)及代碼實(shí)例

    這篇文章主要介紹了Javaweb EL自定義函數(shù)開發(fā)及代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • mybatis-plus的批量新增/批量更新以及問題

    mybatis-plus的批量新增/批量更新以及問題

    這篇文章主要介紹了Mybatis-Plus實(shí)現(xiàn)批量新增與批量更新以及出現(xiàn)的問題,文章中有詳細(xì)的代碼示例,感興趣的同學(xué)可以參考一下
    2023-04-04
  • java中的BlockingQueue(阻塞隊(duì)列)解析

    java中的BlockingQueue(阻塞隊(duì)列)解析

    這篇文章主要介紹了java中的BlockingQueue阻塞隊(duì)列解析,阻塞隊(duì)列是一個(gè)支持兩個(gè)附加操作的隊(duì)列,這兩個(gè)附加的操作是,在隊(duì)列為空時(shí),獲取元素的線程會(huì)等待隊(duì)列變?yōu)榉强?需要的朋友可以參考下
    2023-12-12

最新評(píng)論