激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java多線程定時器Timer原理及實現

Java多線程定時器Timer原理及實現

2021-02-04 12:06五月的倉頡 Java教程

這篇文章主要介紹了Java多線程定時器Timer原理及實現,涉及Timer的schedule的使用,定時器Timer的schedule等相關內容以及代碼示例,具有一定參考價值,需要的朋友可以了解下。

前言

定時/計劃功能在Java應用的各個領域都使用得非常多,比方說Web層面,可能一個項目要定時采集話單、定時更新某些緩存、定時清理一批不活躍用戶等等。定時計劃任務功能在Java中主要使用的就是Timer對象,它在內部使用多線程方式進行處理,所以它和多線程技術關聯還是相當大的。那和ThreadLocal一樣,還是先講原理再講使用,Timer的實現原理不難,就簡單掃一下就好了。

Timer的schedule(TimeTask task, Date time)的使用

該方法的作用是在執行的日期執行一次任務

1、執行任務的時間晚于當前時間:未來執行

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static Timer timer = new Timer();
static public class MyTask extends TimerTask
{
  public void run()
  {
    System.out.println("運行了!時間為:" + new Date());
  }
}
public static void main(String[] args) throws Exception
{
  MyTask task = new MyTask();
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString = "2015-10-6 12:14:00";
  Date dateRef = sdf.parse(dateString);
  System.out.println("字符串時間:" + dateRef.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(task, dateRef);
}

看一下運行效果:

?
1
2
字符串時間:2015-10-6 12:14:00 當前時間:2015-10-6 12:13:23
運行了!時間為:Tue Oct 06 12:14:00 CST 2015

執行時間和但前時間不一致,而是和dateRef的時間一直,證明了未來執行。任務雖然執行完了,但進程沒有銷毀,控制臺上的方框可以看到還是紅色的,看下Timer的源代碼:

?
1
2
3
public Timer() {
  this("Timer-" + serialNumber());
}
?
1
2
3
4
public Timer(String name) {
  thread.setName(name);
  thread.start();
}

所以,啟動一個Timer就是啟動一個新線程,但是這個新線程并不是守護線程,所以它會一直運行。要運行完就讓進程停止的話,設置Timer為守護線程就好了,有專門的構造函數可以設置:

?
1
2
3
public Timer(boolean isDaemon) {
  this("Timer-" + serialNumber(), isDaemon);
}
?
1
2
3
4
5
public Timer(String name, boolean isDaemon) {
  thread.setName(name);
  thread.setDaemon(isDaemon);
  thread.start();
}

2、計劃時間早于當前時間:立即執行

如果執行任務的時間早于當前時間,那么立即執行task的任務:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static Timer timer = new Timer();
static public class MyTask extends TimerTask
{
  public void run()
  {
    System.out.println("運行了!時間為:" + new Date());
  }
}
public static void main(String[] args) throws Exception
{
  MyTask task = new MyTask();
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString = "2014-10-6 12:14:00";
  Date dateRef = sdf.parse(dateString);
  System.out.println("字符串時間:" + dateRef.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(task, dateRef);
}

看一下運行效果:

?
1
2
字符串時間:2014-10-6 12:14:00 當前時間:2015-10-6 12:20:10
運行了!時間為:Tue Oct 06 12:20:10 CST 2015

執行時間和當前時間一致,證明了立即執行

3、多個TimerTask任務執行

Timer中允許有多個任務:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static Timer timer = new Timer();
static public class MyTask extends TimerTask
{
  public void run()
  {
    System.out.println("運行了!時間為:" + new Date());
  }
}
public static void main(String[] args) throws Exception
{
  MyTask task1 = new MyTask();
  MyTask task2 = new MyTask();
  SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString1 = "2015-10-6 12:26:00";
  String dateString2 = "2015-10-6 12:27:00";
  Date dateRef1 = sdf1.parse(dateString1);
  Date dateRef2 = sdf2.parse(dateString2);
  System.out.println("字符串時間:" + dateRef1.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  System.out.println("字符串時間:" + dateRef2.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(task1, dateRef1);
  timer.schedule(task2, dateRef2);
}

看一下運行結果:

字符串時間:2015-10-612:26:00當前時間:2015-10-612:25:38

字符串時間:2015-10-612:27:00當前時間:2015-10-612:25:38

運行了!時間為:TueOct0612:26:00CST2015

運行了!時間為:TueOct0612:27:00CST2015

可以看到,運行時間和設置的時間一致,證明了未來可以執行多個任務。另外注意,Task是以隊列的方式一個一個被順序執行的,所以執行的時間有可能和預期的時間不一致,因為前面的任務可能消耗過長,后面任務的運行時間也有可能被延遲。

代碼就不寫了,舉個例子,任務1計劃12:00:00被執行,任務2計劃12:00:10被執行,結果任務1執行了30秒,那么任務2將在12:00:30被執行,因為Task是被放入隊列中的,因此必須一個一個順序運行。

Timer的schedule(TimerTasktask,DatefirstTime,longperiod)

該方法的作用是在指定的日期之后,按指定的間隔周期性地無限循環地執行某一人物

1、計劃時間晚于當前時間:未來執行

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static public class MyTask extends TimerTask
{
  public void run()
  {
    System.out.println("運行了!時間為:" + new Date());
  }
}
public static void main(String[] args) throws Exception
{
  MyTask task = new MyTask();
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString = "2015-10-6 18:00:00";
  Timer timer = new Timer();
  Date dateRef = sdf.parse(dateString);
  System.out.println("字符串時間:" + dateRef.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(task, dateRef, 4000);
}

看一下運行結果:

字符串時間:2015-10-6 18:01:00 當前時間:2015-10-6 18:00:15
運行了!時間為:Tue Oct 06 18:01:00 CST 2015
運行了!時間為:Tue Oct 06 18:01:04 CST 2015
運行了!時間為:Tue Oct 06 18:01:08 CST 2015
運行了!時間為:Tue Oct 06 18:01:12 CST 2015
...

看到從設定的時間開始,每隔4秒打印一次,無限打印下去

2、計劃時間早于當前時間:立即執行

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static public class MyTask extends TimerTask
{
  public void run()
  {
    System.out.println("運行了!時間為:" + new Date());
  }
}
public static void main(String[] args) throws Exception
{
  MyTask task = new MyTask();
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString = "2014-10-6 18:01:00";
  Timer timer = new Timer();
  Date dateRef = sdf.parse(dateString);
  System.out.println("字符串時間:" + dateRef.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(task, dateRef, 4000);
}

看一下運行結果:

字符串時間:2014-10-6 18:01:00 當前時間:2015-10-6 18:02:46
運行了!時間為:Tue Oct 06 18:02:46 CST 2015
運行了!時間為:Tue Oct 06 18:02:50 CST 2015
運行了!時間為:Tue Oct 06 18:02:54 CST 2015
運行了!時間為:Tue Oct 06 18:02:58 CST 2015
運行了!時間為:Tue Oct 06 18:03:02 CST 2015
...

看到運行時間比當前時間早,從當前時間開始,每隔4秒打印一次,無限循環下去

TimerTask的cancel()方法

TimerTask的cancel()方法的作用是將自身從任務隊列中清除:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
static public class MyTaskA extends TimerTask
{
  public void run()
  {
    System.out.println("A運行了!時間為:" + new Date());
    this.cancel();
  }
}
  
static public class MyTaskB extends TimerTask
{
  public void run()
  {
    System.out.println("B運行了!時間為:" + new Date());
  }
}
  
public static void main(String[] args) throws Exception
{
  MyTaskA taskA = new MyTaskA();
  MyTaskB taskB = new MyTaskB();
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString = "2015-10-6 18:10:00";
  Timer timer = new Timer();
  Date dateRef = sdf.parse(dateString);
  System.out.println("字符串時間:" + dateRef.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(taskA, dateRef, 4000);
  timer.schedule(taskB, dateRef, 4000); 
}

看一下運行結果:

?
1
2
3
4
5
6
7
字符串時間:2015-10-6 18:10:00 當前時間:2015-10-6 18:09:47
A運行了!時間為:Tue Oct 06 18:10:00 CST 2015
B運行了!時間為:Tue Oct 06 18:10:00 CST 2015
B運行了!時間為:Tue Oct 06 18:10:04 CST 2015
B運行了!時間為:Tue Oct 06 18:10:08 CST 2015
B運行了!時間為:Tue Oct 06 18:10:12 CST 2015
...

看到TimeTask的cancel()方法是將自身從任務隊列中被移除,其他任務不受影響

Timer的cancel()方法

把上面代碼改動一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private static Timer timer = new Timer();
  
static public class MyTaskA extends TimerTask
{
  public void run()
  {
    System.out.println("A運行了!時間為:" + new Date());
    timer.cancel();
  }
}
  
static public class MyTaskB extends TimerTask
{
  public void run()
  {
    System.out.println("B運行了!時間為:" + new Date());
  }
}
  
public static void main(String[] args) throws Exception
{
  MyTaskA taskA = new MyTaskA();
  MyTaskB taskB = new MyTaskB();
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  String dateString = "2015-10-6 18:10:00";
  Date dateRef = sdf.parse(dateString);
  System.out.println("字符串時間:" + dateRef.toLocaleString() + " 當前時間:" + new Date().toLocaleString());
  timer.schedule(taskA, dateRef, 4000);
  timer.schedule(taskB, dateRef, 4000);
}

看一下運行結果:

字符串時間:2015-10-618:10:00當前時間:2015-10-618:14:15

A運行了!時間為:TueOct0618:14:15CST2015

全部任務都被清除,并且進程被銷毀。不過注意一下,cancel()方法未必一定會停止執行計劃任務,可能正常執行,因為cancel()方法會嘗試去獲取queue鎖,如果并沒有獲取到queue鎖的話,TimerTask類中的任務繼續執行也是完全有可能的

其他方法

再列舉一些Timer中的其他schedule的重載方法的作用,就不提供證明的代碼了,可以自己嘗試一下:

1、schedule(TimerTasktask,longdelay)

以當前時間為參考,在此時間基礎上延遲指定的毫秒數后執行一次TimerTask任務

2、schedule(TimerTasktask,longdelay,longperiod)

以當前時間為參考,在此時間基礎上延遲指定的毫秒數后,以period為循環周期,循環執行TimerTask任務

3、scheduleAtFixedRate(TimerTasktask,DatefirstTime,longperiod)

在延時的場景下,schedule方法和scheduleAtFixedRate方法沒有區別,它們的區別只是在非延時上。如果執行任務的時間沒有被延時,對于schedule方法來說,下一次任務執行的時間參考的是上一次任務的開始時間來計算的;對于scheduleAtFixedRate方法來說,下一次任務執行的時間參考的是上一次任務的結束時間來計算的

總結

以上就是本文關于Java多線程定時器Timer原理及實現的全部內容,希望對大家有所幫助。如有不足之處,歡迎留言指出。

原文鏈接:https://www.cnblogs.com/xrq730/p/4856985.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 欧美精品激情在线 | 成片免费观看大全 | 黄色免费播放网站 | 国产免费黄色 | 一级影片在线观看 | 亚州欧美在线 | 亚洲看片网 | 国产精品一区免费在线观看 | 欧美黄一区 | 99视频有精品视频高清 | 老司机免费福利午夜入口ae58 | 国产好片无限资源 | 综合图区亚洲 | 午夜精品久久久久久久爽 | 久久毛片免费观看 | 精品国产91久久久久久久妲己 | 视频一区二区三区在线 | 国产日韩在线 | 91精品国产91久久久久久 | 人与xxxxhdxxxhdxx| 黄视频免费在线观看 | 精品无码久久久久久国产 | 毛片网站网址 | 国产一区在线观看视频 | 毛片电影网址 | 亚洲国产视频在线 | 日本一区二区久久久 | 久久久综合视频 | 在线观看国产免费视频 | 久久久久.com| 国产亚洲精品综合一区91 | 久久av免费 | 日韩免费黄色 | 91精品国产九九九久久久亚洲 | 污视频在线免费 | 成人福利免费在线观看 | 久久网日本 | 性色av一区二区三区在线播放亚… | 在线观看视频毛片 | 九艹在线 | 一级一级一级毛片 |