0%

java | ScheduledThreadPoolExecutor 使用

任务调度线程池。

Timer 缺点

在「任务调度线程池」功能加入之前,可以使用 java.util.Timer 来实现定时功能,Timer 的有点在于简单。

但是,由于所有任务都是由一个线程来调度,因此,所有的任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。

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
31
32
33
package com.redisc;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.*;

@Slf4j(topic = "c.Test")
public class Run {

public static void main(String[] args) throws InterruptedException, ExecutionException {
Timer timer = new Timer();
TimerTask task1 = new TimerTask() {
@SneakyThrows
@Override
public void run() {
log.debug("task1");
Thread.sleep(2000);
}
};
TimerTask task2 = new TimerTask() {
@Override
public void run() {
log.debug("task2");
}
};

log.debug("start...");
timer.schedule(task1,1000);
timer.schedule(task2,1000);
}
}

期望两个任务都是 1 秒后执行,但是,实际输出

1
2
3
22:56:02.714 [main] DEBUG c.Test - start...
22:56:03.719 [Timer-0] DEBUG c.Test - task1
22:56:05.723 [Timer-0] DEBUG c.Test - task2

如果 task1 有异常,那么,task2 不会执行。

ScheduledThreadPoolExecutor 基本用法

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
package com.redisc;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.*;

@Slf4j(topic = "c.Test")
public class Run {

public static void main(String[] args) throws InterruptedException, ExecutionException {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

pool.schedule(() -> {
log.debug("task1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 1, TimeUnit.SECONDS);

pool.schedule(() -> {
log.debug("task2");
}, 1, TimeUnit.SECONDS);
}
}

输出

1
2
22:14:16.744 [pool-1-thread-2] DEBUG c.Test - task2
22:14:16.744 [pool-1-thread-1] DEBUG c.Test - task1

两个同时执行。即便是任务出现异常,也不影响其他线程。

ScheduledThreadPoolExecutor 定时执行

scheduleAtFixedRate

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
package com.redisc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j(topic = "c.Test")
public class Run {

public static void main(String[] args) throws InterruptedException, ExecutionException {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);

pool.scheduleAtFixedRate(() -> {
log.debug("1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 1, 1, TimeUnit.SECONDS);

}
}

输出

1
2
3
4
5
22:25:27.925 [pool-1-thread-1] DEBUG c.Test - 1
22:25:29.931 [pool-1-thread-1] DEBUG c.Test - 1
22:25:31.932 [pool-1-thread-1] DEBUG c.Test - 1
22:25:33.934 [pool-1-thread-1] DEBUG c.Test - 1
22:25:35.935 [pool-1-thread-1] DEBUG c.Test - 1

仔细看,任务共消耗 2s,当执行完任务后,其就立刻执行。

scheduleWithFixedDelay

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
package com.redisc;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j(topic = "c.Test")
public class Run {

public static void main(String[] args) throws InterruptedException, ExecutionException {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);

pool.scheduleWithFixedDelay(() -> {
log.debug("1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 1, 1, TimeUnit.SECONDS);
}
}

输出

1
2
3
4
22:27:40.122 [pool-1-thread-1] DEBUG c.Test - 1
22:27:43.130 [pool-1-thread-1] DEBUG c.Test - 1
22:27:46.137 [pool-1-thread-1] DEBUG c.Test - 1
22:27:49.145 [pool-1-thread-1] DEBUG c.Test - 1

任务执行完毕,然后又开始延迟 1s 执行。

请我喝杯咖啡吧~