一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 亚洲国产精品一区二区久久 | 国产精品久久久久久久久免费 | 亚洲天天做夜夜做天天欢 | 国产麻豆剧果冻传媒观看免费视频 | 99精品视频在线观看re | 午夜精品久久久久久久99蜜桃 | 出轨同学会免费观看 | 丝瓜视频黄色在线观看 | 亚洲日韩欧美一区二区在线 | 幻女free性zozo交体内谢 | 男女乱淫真视频播放网站 | 国产精品国产色综合色 | 欧美在线视频一区在线观看 | 亚洲AV无码乱码国产麻豆穿越 | 日本免费在线观看视频 | 999久久久| 久久中文字幕乱码免费 | 日本三级免费网站 | 女女同性做爰xxoo亲吻 | 久久精品国产亚洲AV天美18 | 国产精品日韩欧美一区二区 | 秋霞在线观看成人高清视频51 | 久久婷婷五月综合色精品首页 | gogort99人体专业网站 | 日本不卡在线视频高清免费 | 久久国产精品高清一区二区三区 | www.色.con | 国产精品区一区二区免费 | 日本xxxxxxxxx高清hd | 亚洲欧美在线免费观看 | 国产综合成人久久大片91 | 村上里沙40分钟在线观看 | 福利国模私拍视频在线观看 | 四大美女思春艳史片 | 免费视频观看 | 91在线精品国产丝袜超清 | 暖暖日本在线观看免费 | 午夜无码片在线观看影院 | 欧美ⅹxxxx视频 | 麻豆小视频在线观看 | 日本五级床片全都免费播放 |