最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)Timer源碼分析

 更新時間:2018年07月12日 08:13:52   作者:狂小白  
這篇文章講述了java并發(fā)編程的相關知識點,并通過Timer源碼分析更深入的講解了java并發(fā)編程。

timer在JDK里面,是很早的一個API了。具有延時的,并具有周期性的任務,在newScheduledThreadPool出來之前我們一般會用Timer和TimerTask來做,但是Timer存在一些缺陷,為什么這么說呢?

Timer只創(chuàng)建唯一的線程來執(zhí)行所有Timer任務。如果一個timer任務的執(zhí)行很耗時,會導致其他TimerTask的時效準確性出問題。例如一個TimerTask每10秒執(zhí)行一次,而另外一個TimerTask每40ms執(zhí)行一次,重復出現的任務會在后來的任務完成后快速連續(xù)的被調用4次,要么完全“丟失”4次調用。Timer的另外一個問題在于,如果TimerTask拋出未檢查的異常會終止timer線程。這種情況下,Timer也不會重新回復線程的執(zhí)行了;它錯誤的認為整個Timer都被取消了。此時已經被安排但尚未執(zhí)行的TimerTask永遠不會再執(zhí)行了,新的任務也不能被調度了。

這里做了一個小的 demo 來復現問題,代碼如下:

package com.hjc;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by cong on 2018/7/12.
 */
public class TimerTest {
 //創(chuàng)建定時器對象
 static Timer timer = new Timer();

 public static void main(String[] args) {
 //添加任務1,延遲500ms執(zhí)行
 timer.schedule(new TimerTask() {

  @Override
  public void run() {
  System.out.println("---one Task---");
  try {
   Thread.sleep(1000);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  throw new RuntimeException("error ");
  }
 }, 500);
 //添加任務2,延遲1000ms執(zhí)行
 timer.schedule(new TimerTask() {

  @Override
  public void run() {
  for (;;) {
   System.out.println("---two Task---");
   try {
   Thread.sleep(1000);
   } catch (InterruptedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   }
  }
  }
 }, 1000);

 }
}

如上代碼先添加了一個任務在 500ms 后執(zhí)行,然后添加了第二個任務在 1s 后執(zhí)行,我們期望的是當第一個任務輸出 ---one Task--- 后等待 1s 后第二個任務會輸出 ---two Task---,

但是執(zhí)行完畢代碼后輸出結果如下所示:

例子2,

public class Shedule {
 private static long start;

 public static void main(String[] args) {
  TimerTask task = new TimerTask() {
   public void run() {
    System.out.println(System.currentTimeMillis()-start);
    try{
     Thread.sleep(3000);
    }catch (InterruptedException e){
     e.printStackTrace();
    }
   }
  };

  TimerTask task1 = new TimerTask() {
   @Override
   public void run() {
    System.out.println(System.currentTimeMillis()-start);
   }
  };

  Timer timer = new Timer();
  start = System.currentTimeMillis();
  //啟動一個調度任務,1S鐘后執(zhí)行
  timer.schedule(task,1000);
  //啟動一個調度任務,3S鐘后執(zhí)行
  timer.schedule(task1,3000);


 }

}

上面程序我們預想是第一個任務執(zhí)行后,第二個任務3S后執(zhí)行的,即輸出一個1000,一個3000.

實際運行結果如下:

實際運行結果并不如我們所愿。世界結果,是過了4S后才輸出第二個任務,即4001約等于4秒。那部分時間時間到哪里去了呢?那個時間是被我們第一個任務的sleep所占用了。

現在我們在第一個任務中去掉Thread.sleep();這一行代碼,運行是否正確了呢?運行結果如下:

可以看到確實是第一個任務過了1S后執(zhí)行,第二個任務在第一個任務執(zhí)行完后過3S執(zhí)行了。

這就說明了Timer只創(chuàng)建唯一的線程來執(zhí)行所有Timer任務。如果一個timer任務的執(zhí)行很耗時,會導致其他TimerTask的時效準確性出問題。

Timer 實現原理分析

下面簡單介紹下 Timer 的原理,如下圖是 Timer 的原理模型介紹:

1.其中 TaskQueue 是一個平衡二叉樹堆實現的優(yōu)先級隊列,每個 Timer 對象內部有唯一一個 TaskQueue 隊列。用戶線程調用 timer 的 schedule 方法就是把 TimerTask 任務添加到 TaskQueue 隊列,在調用 schedule 的方法時候 long delay 參數用來說明該任務延遲多少時間執(zhí)行。

2.TimerThread 是具體執(zhí)行任務的線程,它從 TaskQueue 隊列里面獲取優(yōu)先級最小的任務進行執(zhí)行,需要注意的是只有執(zhí)行完了當前的任務才會從隊列里面獲取下一個任務而不管隊列里面是否有已經到了設置的 delay 時間,一個 Timer 只有一個 TimerThread 線程,所以可知 Timer 的內部實現是一個多生產者單消費者模型。

從實現模型可以知道要探究上面的問題只需看 TimerThread 的實現就可以了,TimerThread 的 run 方法主要邏輯源碼如下:

public void run() {
 try {
  mainLoop();
 } finally {
  // 有人殺死了這個線程,表現得好像Timer已取消
  synchronized(queue) {
   newTasksMayBeScheduled = false;
   queue.clear(); // 消除過時的引用
  }
 }
}
 private void mainLoop() {
  while (true) {
   try {
    TimerTask task;
    boolean taskFired;
    //從隊列里面獲取任務時候要加鎖
    synchronized(queue) {
     ......
    }
    if (taskFired) 
     task.run();//執(zhí)行任務
   } catch(InterruptedException e) {
   }
  }
 }

可知當任務執(zhí)行過程中拋出了除 InterruptedException 之外的異常后,唯一的消費線程就會因為拋出異常而終止,那么隊列里面的其他待執(zhí)行的任務就會被清除。所以 TimerTask 的 run 方法內最好使用 try-catch 結構 catch 主可能的異常,不要把異常拋出到 run 方法外。

其實要實現類似 Timer 的功能使用 ScheduledThreadPoolExecutor 的 schedule 是比較好的選擇。ScheduledThreadPoolExecutor 中的一個任務拋出了異常,其他任務不受影響的。

ScheduledThreadPoolExecutor 例子如下:

/**
 * Created by cong on 2018/7/12.
 */
public class ScheduledThreadPoolExecutorTest {
 static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1);

 public static void main(String[] args) {

  scheduledThreadPoolExecutor.schedule(new Runnable() {

   public void run() {
    System.out.println("---one Task---");
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    throw new RuntimeException("error ");
   }

  }, 500, TimeUnit.MICROSECONDS);

  scheduledThreadPoolExecutor.schedule(new Runnable() {

   public void run() {
    for (int i =0;i<5;++i) {
     System.out.println("---two Task---");
     try {
      Thread.sleep(1000);
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
    }

   }

  }, 1000, TimeUnit.MICROSECONDS);

  scheduledThreadPoolExecutor.shutdown();
 }
}

運行結果如下:

之所以 ScheduledThreadPoolExecutor 的其他任務不受拋出異常的任務的影響是因為 ScheduledThreadPoolExecutor 中的 ScheduledFutureTask 任務中 catch 掉了異常,但是在線程池任務的 run 方法內使用 catch 捕獲異常并打印日志是最佳實踐。

相關文章

  • Java接口測試Cookie與token原理解析

    Java接口測試Cookie與token原理解析

    這篇文章主要介紹了Java接口測試Cookie與token原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • springboot實現FastJson解析json數據的方法

    springboot實現FastJson解析json數據的方法

    本篇文章主要介紹了springboot實現FastJson解析json數據的方法,非常具有實用價值,需要的朋友可以參考下
    2017-04-04
  • 如何理解SpringMVC

    如何理解SpringMVC

    Spring Web MVC是一種基于Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基于請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發(fā)
    2021-06-06
  • eclipse怎么引入spring boot項目插件的方法

    eclipse怎么引入spring boot項目插件的方法

    這篇文章主要介紹了eclipse怎么引入spring boot項目插件的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-06-06
  • Spring?Security認證器實現過程詳解

    Spring?Security認證器實現過程詳解

    一些權限框架一般都包含認證器和決策器,前者處理登陸驗證,后者處理訪問資源的控制,這篇文章主要介紹了Spring?Security認證器實現過程,需要的朋友可以參考下
    2022-06-06
  • SpringMVC通過攔截器實現IP黑名單

    SpringMVC通過攔截器實現IP黑名單

    這篇文章主要為大家詳細介紹了SpringMVC通過攔截器實現IP黑名單,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Java異常分類及統(tǒng)一處理詳解

    Java異常分類及統(tǒng)一處理詳解

    這篇文章主要為大家詳細介紹了Java異常分類及統(tǒng)一處理,SpringMVC處理異常支持ajax,web.xml配置異常,感興趣的小伙伴們可以參考一下
    2016-03-03
  • java實現簡單日期計算功能

    java實現簡單日期計算功能

    這篇文章主要為大家詳細介紹了java實現簡單日期計算功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-11-11
  • 淺談JackSon的幾種用法

    淺談JackSon的幾種用法

    這篇文章主要介紹了淺談JackSon的幾種用法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • 詳解java CountDownLatch和CyclicBarrier在內部實現和場景上的區(qū)別

    詳解java CountDownLatch和CyclicBarrier在內部實現和場景上的區(qū)別

    這篇文章主要介紹了詳解java CountDownLatch和CyclicBarrier在內部實現和場景上的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05

最新評論

砀山县| 毕节市| 高淳县| 龙里县| 贵州省| 上饶县| 永新县| 克拉玛依市| 邵阳县| 库车县| 张家口市| 英超| 中牟县| 巫溪县| 东至县| 额尔古纳市| 寿阳县| 石林| 广东省| 阿巴嘎旗| 杂多县| 秦安县| 色达县| 赤城县| 宿迁市| 南郑县| 时尚| 浦城县| 双流县| 花莲县| 麻栗坡县| 乌兰察布市| 三亚市| 遵义县| 裕民县| 花莲县| 扎鲁特旗| 南丰县| 重庆市| 绍兴市| 哈尔滨市|