本文最后更新于: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);
public static void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { throw new RuntimeException(e); } }
public static CompletableFuture<Void> setTimeout(long ms) { return CompletableFuture.runAsync(() -> sleep(ms)); }
public static CompletableFuture<Void> waitResource(Supplier<Boolean> condition) { return CompletableFuture.runAsync(() -> { while (!condition.get()) { sleep(100); } }); }
public static CompletableFuture<Void> setInterval(long ms, Runnable runnable) { return CompletableFuture.runAsync(() -> { 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); } }
|