使用 Java 实现 setTimeout/setInterval

本文最后更新于:2020年12月30日 凌晨

场景

之前想把 Java 代码中使用回调函数的方法改成 Promise 风格,苦思冥想而不得其解。然而突发奇想之下,吾辈尝试在 Java 中实现 JavaScript 的 setTimeout/setInterval,并在之后想到了如何封装回调为 Promise,所以便先在此将这个想法的写出来以供参考。

Promise 是 ES6 添加的一个重要的元素,它将回调函数压平为了一级调用,并在 ES7 的 async/await 中彻底改变了异步的使用方式!

实现

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class AsyncUtil {
private static final Logger log = LoggerFactory.getLogger(AsyncUtil.class);

/**
* 将当前线程休眠指定的时间
*
* @param millis 毫秒
*/
public static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

/**
* 实现 JavaScript 中的 setTimeout
* 注:由于 {@link CompletableFuture#cancel(boolean)} 方法的限制,该定时器无法强制取消
*
* @param ms 等待时间
* @return 异步对象
*/

public static CompletableFuture<Void> setTimeout(long ms) {
return CompletableFuture.runAsync(() -> sleep(ms));
}

/**
* 实现等待指定资源加载完成
* 注:由于 {@link CompletableFuture#cancel(boolean)} 方法的限制,该定时器无法强制取消
*
* @param condition 临界条件
* @return 异步对象
*/
public static CompletableFuture<Void> waitResource(Supplier<Boolean> condition) {
return CompletableFuture.runAsync(() -> {
while (!condition.get()) {
sleep(100);
}
});
}

/**
* 实现 JavaScript 中的 setInterval 周期函数
* 该方法并不是非常精确的定时器,仅适用于一般场景,如有需要请使用 {@link ScheduledExecutorService} 类
* 注:由于 {@link CompletableFuture#cancel(boolean)} 方法的限制,该定时器无法强制取消
*
* @param ms 间隔毫秒数
* @param runnable 回调函数
* @return 永远不会完成的异步对象
*/
public static CompletableFuture<Void> setInterval(long ms, Runnable runnable) {
return CompletableFuture.runAsync(() -> {
//noinspection InfiniteLoopStatement
while (true) {
try {
runnable.run();
sleep(ms);
} catch (Exception e) {
log.error("使用 setInterval 发生异常: ", e);
}
}
});
}
}

使用

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
34
35
36
37
public class AsyncUtilTest {
private final Logger log = LoggerFactory.getLogger(getClass());

public static void main(String[] args) {
final AsyncUtilTest asyncUtilTest = new AsyncUtilTest();
asyncUtilTest.setTimeout();
asyncUtilTest.waitResource();
asyncUtilTest.setInterval();
AsyncUtil.sleep(4000);
}

@Test
public void setTimeout() {
log.info("setTimeout completed before time: {}", LocalDateTime.now());
AsyncUtil.setTimeout(1000)
.thenRunAsync(() -> log.info("setTimeout completed after time: {}", LocalDateTime.now()));
}

@Test
public void waitResource() {
log.info("waitResource completed before time: {}", LocalDateTime.now());
final AtomicInteger i = new AtomicInteger(1);
AsyncUtil.waitResource(() -> i.get() == 3)
.thenRunAsync(() -> log.info("waitResource completed after time: {}", LocalDateTime.now()));
AsyncUtil.sleep(2);
i.set(3);
}

@Test
public void setInterval() {
log.info("setInterval completed before time: {}", LocalDateTime.now());
final CompletableFuture<Void> future = AsyncUtil.setInterval(100, () -> log.info("setInterval in the loop, current time: {}", LocalDateTime.now()));
AsyncUtil.sleep(500);
future.complete(null);
AsyncUtil.sleep(1000);
}
}

使用 Java 实现 setTimeout/setInterval
https://blog.rxliuli.com/p/50931c01eb444f7abe80042ca54721f7/
作者
rxliuli
发布于
2020年4月18日
许可协议