這篇具有很好參考價值的文章主要介紹了周期性線程池 newScheduledThreadPool。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。
newScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}
ScheduledThreadPoolExecutor繼承自ThreadPoolExecutor。它主要用來在給定的延遲 之后運(yùn)行任務(wù),或者定期執(zhí)行任務(wù) 。ScheduledThreadPoolExecutor的功能與Timer類似,但ScheduledThreadPoolExecutor功能更強(qiáng)大、更靈活。Timer對應(yīng)的是單個后臺線程 ,而ScheduledThreadPoolExecutor可以在構(gòu)造函數(shù)中指定多個 對應(yīng)的后臺線程數(shù)。 |
|
Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically. |
|
DelayQueue 是一個無界隊列,所以ThreadPoolExecutor的maximumPoolSize 在Scheduled-ThreadPoolExecutor中沒有什么意義(設(shè)置maximumPoolSize的大小沒有什么效果)。 |
ScheduledThreadPoolExecutor 的執(zhí)行主要分為兩大部分。 |
1)當(dāng)調(diào)用ScheduledThreadPoolExecutor的scheduleAtFixedRate() 方法或者scheduleWithFixedDelay() 方法時,會向ScheduledThreadPoolExecutor的DelayQueue 添加一個實現(xiàn)了RunnableScheduledFutur 接口的ScheduledFutureTask 。 |
2)線程池中的線程從DelayQueue中獲取ScheduledFutureTask ,然后執(zhí)行任務(wù)。 |
ScheduledThreadPoolExecutor的實現(xiàn)
ScheduledThreadPoolExecutor會把待調(diào)度的任務(wù)(ScheduledFutureTask )放到一個DelayQueue 中。 |
|
ScheduledFutureTask 主要包含3個成員變量,如下。 |
·long型成員變量time,表示這個任務(wù)將要被執(zhí)行的具體時間 。 |
·long型成員變量sequenceNumber,表示這個任務(wù)被添加到ScheduledThreadPoolExecutor中的序號 。 |
·long型成員變量period,表示任務(wù)執(zhí)行的間隔周期 。 |
|
DelayQueue 封裝了一個 PriorityQueue ,這個PriorityQueue會對隊列中的Scheduled-FutureTask進(jìn)行排序。排序時,time 小的排在前面(時間早的任務(wù)將被先執(zhí)行)。如果兩個ScheduledFutureTask的time相同,就比較sequenceNumber ,sequenceNumber小的排在前面(也就是說,如果兩個任務(wù)的執(zhí)行時間相同,那么先提交的任務(wù)將被先執(zhí)行)。 |
|
下圖是ScheduledThreadPoolExecutor中的線程1 執(zhí)行某個周期任務(wù)的4個步驟。 |

|
1)線程1從DelayQueue中獲取已到期 的ScheduledFutureTask(DelayQueue.take())。到期任務(wù)是指ScheduledFutureTask的time大于等于當(dāng)前時間。 |
2)線程1執(zhí)行 這個ScheduledFutureTask。 |
3)線程1修改 ScheduledFutureTask的time 變量為下次將要被執(zhí)行的時間。 |
4)線程1把這個修改time之后的ScheduledFutureTask放回 DelayQueue中(Delay-Queue.add() )。 |
獲取任務(wù)的過程

獲取任務(wù)分為3大步驟 |
1)獲取Lock。 |
2)獲取周期任務(wù)。 |
·如果PriorityQueue為空,當(dāng)前線程到Condition中等待 ;否則執(zhí)行下面的2.2。 |
·如果PriorityQueue的頭元素的time時間比當(dāng)前時間大,到Condition中等待到time時間 ;否則執(zhí)行下面的2.3。 |
·獲取 PriorityQueue的頭元素(2.3.1);如果PriorityQueue不為空,則喚醒 在Condition中等待的所有線程(2.3.2)。 |
3)釋放Lock。 |
ScheduledThreadPoolExecutor在一個循環(huán)中執(zhí)行步驟2,直到線程從PriorityQueue獲取到一個元素之后(執(zhí)行2.3.1之后),才會退出無限循環(huán) (結(jié)束步驟2)。 |
|
把ScheduledFutureTask放入DelayQueue中的過程

添加任務(wù)分為3大步驟。 |
1)獲取Lock。 |
2)添加任務(wù)。 |
·向PriorityQueue添加任務(wù)。 |
·如果在上面2.1中添加 的任務(wù)是PriorityQueue的頭元素,喚醒 在Condition中等待的所有線程。 |
3)釋放Lock。 |
-----------------------------------------------------------------------------讀書筆記摘自 書名:Java并發(fā)編程的藝術(shù) 作者:方騰飛;魏鵬;程曉明文章來源:http://www.zghlxwxcb.cn/news/detail-453505.html
常見用途
參考:Executor框架的成員文章來源地址http://www.zghlxwxcb.cn/news/detail-453505.html
線程任務(wù)
public class Task implements Runnable {
private final String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " → " + name + " Start Time = " + new Date());
processCommand();
System.out.println(Thread.currentThread().getName() + " → " + name + " End Time = " + new Date());
}
private void processCommand() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1. schedule(new Task(), 10, TimeUnit.SECONDS)
public class ScheduledThreadPool {
public static void main(String args[]) throws InterruptedException, ExecutionException {
System.out.println(Thread.currentThread().getName() + "線程: Start at: " + new Date());
ScheduledThreadPoolExecutor exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(5);
for (int i = 0; i < 10; i++) {
System.out.println("添加了第" + i + "個線程任務(wù) " + new Date());
exec.schedule(new Task("線程名字" + i), 10, TimeUnit.SECONDS);
}
exec.shutdown();
System.out.println(Thread.currentThread().getName() + "線程: 打卡" + new Date());
while (!exec.isTerminated()) {
}
System.out.println(Thread.currentThread().getName() + "線程: Finished all threads at:" + new Date());
}
}
執(zhí)行結(jié)果分析
執(zhí)行結(jié)果 |
main線程: Start at: Sat May 20 12:51:32 CST 2023 |
添加了第0個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第1個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第2個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第3個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第4個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第5個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第6個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第7個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第8個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
添加了第9個線程任務(wù) Sat May 20 12:51:32 CST 2023 |
main線程: 打卡Sat May 20 12:51:32 CST 2023 |
pool-1-thread-5 → 線程名字2 Start Time = Sat May 20 12:51:42 CST 2023 |
pool-1-thread-3 → 線程名字1 Start Time = Sat May 20 12:51:42 CST 2023 |
pool-1-thread-4 → 線程名字3 Start Time = Sat May 20 12:51:42 CST 2023 |
pool-1-thread-2 → 線程名字4 Start Time = Sat May 20 12:51:42 CST 2023 |
pool-1-thread-1 → 線程名字0 Start Time = Sat May 20 12:51:42 CST 2023 |
pool-1-thread-3 → 線程名字1 End Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-5 → 線程名字2 End Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-3 → 線程名字5 Start Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-5 → 線程名字6 Start Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-4 → 線程名字3 End Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-4 → 線程名字7 Start Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-2 → 線程名字4 End Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-2 → 線程名字8 Start Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-1 → 線程名字0 End Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-1 → 線程名字9 Start Time = Sat May 20 12:51:45 CST 2023 |
pool-1-thread-3 → 線程名字5 End Time = Sat May 20 12:51:48 CST 2023 |
pool-1-thread-5 → 線程名字6 End Time = Sat May 20 12:51:48 CST 2023 |
pool-1-thread-4 → 線程名字7 End Time = Sat May 20 12:51:48 CST 2023 |
pool-1-thread-2 → 線程名字8 End Time = Sat May 20 12:51:48 CST 2023 |
pool-1-thread-1 → 線程名字9 End Time = Sat May 20 12:51:48 CST 2023 |
main線程: Finished all threads at:Sat May 20 12:51:48 CST 2023 |
|
從控制臺結(jié)果可以看出: |
5 個線程去執(zhí)行10 個線程任務(wù),線程任務(wù)放到線程池后延遲10 秒執(zhí)行 |
scheduleAtFixedRate() |
scheduleWithFixedDelay() |
以固定的 頻率 執(zhí)行 |
以固定的 延時 執(zhí)行 |
period (周期)指的是兩次成功執(zhí)行之間的時間。 上一個任務(wù)開始的時間計時,一個period后,檢測上一個任務(wù)是否執(zhí)行完畢, 如果上一個任務(wù)執(zhí)行完畢,則當(dāng)前任務(wù)立即執(zhí)行, 如果上一個任務(wù)沒有執(zhí)行完畢,則需要等上一個任務(wù)執(zhí)行完畢后立即執(zhí)行。 |
delay (延時)指的是一次執(zhí)行終止和下一次執(zhí)行開始之間的延遲。 |
|
|
2. scheduleWithFixedDelay(new Task(), 2, 4, TimeUnit.SECONDS) 初始延時 2s, 固定延時4s
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
參數(shù) |
含義 |
command |
the task to execute |
initialDelay |
the time to delay first execution |
delay |
the delay between the termination of one execution and the commencement of the next |
unit |
the time unit of the initialDelay and delay parameters |
public class FixedDelay {
public static void main(String args[]) throws InterruptedException, ExecutionException {
way1();
way2();
}
private static void way2() {
System.out.println(Thread.currentThread().getName() + "線程: Start at: " + new Date());
ScheduledThreadPoolExecutor scheduledExecutorService = new ScheduledThreadPoolExecutor(1);
scheduledExecutorService.scheduleWithFixedDelay(() -> {
System.out.println(Thread.currentThread().getName() + " → " + " Start Time = " + new Date());
try {
sleep(3000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + " → " + " End Time = " + new Date());
}, 1, 4, TimeUnit.SECONDS);
}
private static void way1() {
System.out.println(Thread.currentThread().getName() + "線程: Start at: " + new Date());
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
scheduledExecutorService.scheduleWithFixedDelay(new Task("任務(wù)"), 1, 4, TimeUnit.SECONDS);
}
}
執(zhí)行結(jié)果分析
執(zhí)行結(jié)果 |
分析 |
main線程: Start at: Sat May 20 18:54:29 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 18:54:30 CST 2023 |
延遲 1 s |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 18:54:33 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 18:54:37 CST 2023 |
等待 4 s 再開始 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 18:54:40 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 18:54:44 CST 2023 |
等待 4 s 再開始 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 18:54:47 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 18:54:51 CST 2023 |
等待 4 s 再開始 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 18:54:54 CST 2023 |
|
3. scheduleAtFixedRate(new Task(), 1, 4, TimeUnit.SECONDS) 初始延時 1s, 周期4s
執(zhí)行結(jié)果分析
執(zhí)行結(jié)果 |
分析 |
前置條件 |
任務(wù)用時 3 秒, period = 4 秒 |
main線程: Starting at: Sat May 20 19:31:13 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:31:14 CST 2023 |
延時 1 秒 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:31:17 CST 2023 |
任務(wù)用時 3 秒 |
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:31:18 CST 2023 |
period (周期) 4 秒 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:31:21 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:31:22 CST 2023 |
|
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:31:25 CST 2023 |
|
|
|
任務(wù)用時 < period (周期) ,等待時長為:period |
需要等待period 再開始下一個 |
|
|
前置條件 |
任務(wù)用時 3 秒, period = 3 秒 |
main線程: Starting at: Sat May 20 19:35:33 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:35:34 CST 2023 |
|
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:35:37 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:35:37 CST 2023 |
period (周期) 3 秒 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:35:40 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:35:40 CST 2023 |
|
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:35:43 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:35:43 CST 2023 |
|
|
|
任務(wù)用時 = period (周期) ,等待時長為:period |
需要等待period 再開始下一個 |
|
|
|
|
前置條件 |
任務(wù)用時 3 秒, period = 2 秒 |
main線程: Starting at: Sat May 20 19:37:03 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:37:04 CST 2023 |
|
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:37:07 CST 2023 |
|
pool-1-thread-1 → 任務(wù) Start Time = Sat May 20 19:37:07 CST 2023 |
period (周期) 2 秒 無效,以任務(wù)用時為準(zhǔn),故結(jié)束就開始 |
pool-1-thread-1 → 任務(wù) End Time = Sat May 20 19:37:10 CST 2023 |
|
|
|
任務(wù)用時 > period (周期) 4 秒 ,等待時長為:任務(wù)用時 |
等任務(wù)結(jié)束后直接開始執(zhí)行下一個 |
定時任務(wù)?每天晚上9點(diǎn)執(zhí)行一次
public class FixedRateDemo {
public static void main(String args[]) throws InterruptedException, ExecutionException, ParseException {
System.out.println(Thread.currentThread().getName() + "線程: Starting at: " + new Date());
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
long oneDayPeriod = 10000;
long initDelay = getTimeMillis("21:00:00") - getTimeMillis("21:00:03");
initDelay = initDelay > 0 ? initDelay : oneDayPeriod + initDelay;
executor.scheduleAtFixedRate(new Task("定時任務(wù)"), initDelay, oneDayPeriod, TimeUnit.MILLISECONDS);
}
private static long getTimeMillis(String time) throws ParseException {
DateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
DateFormat dayFormat = new SimpleDateFormat("yy-MM-dd");
Date curDate = dateFormat.parse(dayFormat.format(new Date()) + " " + time);
return curDate.getTime();
}
}
執(zhí)行結(jié)果分析
執(zhí)行結(jié)果 |
模擬數(shù)據(jù) |
分析 |
前置條件:模擬20:59:57 開始執(zhí)行定時任務(wù),21:00:00 正式執(zhí)行,周期10 秒 |
|
|
main線程: Starting at: Sat May 20 20:27:54 CST 2023 |
20:59:57 |
開始執(zhí)行時間 |
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:27:57 CST 2023 |
21:00:00 |
當(dāng)天到9 點(diǎn)開始執(zhí)行 |
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:28:00 CST 2023 |
21:00:03 |
任務(wù)執(zhí)行完畢 |
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:28:07 CST 2023 |
21:00:00 |
第2 天9 點(diǎn)重新執(zhí)行 |
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:28:10 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:28:17 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:28:20 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:28:27 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:28:30 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:28:37 CST 2023 |
|
|
|
|
|
|
|
|
前置條件:模擬21:00:03 開始執(zhí)行定時任務(wù),21:00:00 正式執(zhí)行,周期10 秒 |
|
|
main線程: Starting at: Sat May 20 20:41:50 CST 2023 |
21:00:03 |
開始執(zhí)行時間 |
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:41:57 CST 2023 |
21:00:00 |
第2 天9 點(diǎn)開始執(zhí)行 |
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:42:00 CST 2023 |
21:00:03 |
任務(wù)執(zhí)行完畢 |
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:42:07 CST 2023 |
21:00:00 |
第3 天9 點(diǎn)重新執(zhí)行 |
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:42:10 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:42:17 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:42:20 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) Start Time = Sat May 20 20:42:27 CST 2023 |
|
|
pool-1-thread-1 → 定時任務(wù) End Time = Sat May 20 20:42:30 CST 2023 |
|
|
到了這里,關(guān)于周期性線程池 newScheduledThreadPool的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!
本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!