从 Java 基础到掌握 — 第 8 集
安全执行线程和异步操作
该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。
同时运行多个任务可以增加吞吐量,但也会增加共享状态的复杂性。 在决定线程数量之前,您需要决定谁将更改状态以及如何传达完成和失败。
ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(4);
try {
Future<Integer> result = executor.submit(() -> loadScore());
int score = result.get();
System.out.println(score);
} finally {
executor.shutdown();
}
当任务提交给 ExecutorService 时,执行器将管理线程的创建和重用。 Future的get使得当前线程等待完成,同时也会抛出任务异常。
保护共享状态
private final Object lock = new Object();
private int gold;
public void addGold(int amount) {
synchronized (lock) {
gold += amount;
}
}
如果多个线程同时读取和写入相同的值,则操作可能会丢失或可能出现中间状态。 Synchronized 只允许一个线程同时执行使用同一锁的部分。
如果锁范围太宽,等待时间就会增加,并且以不同的顺序获取多个锁可能会导致死锁。 如果可能的话,最好减少可变共享状态本身。
CompletableFuture
CompletableFuture<Player> playerFuture =
CompletableFuture.supplyAsync(this::loadPlayer, executor);
CompletableFuture<List<Item>> itemFuture =
CompletableFuture.supplyAsync(this::loadItems, executor);
CompletableFuture<Void> all =
CompletableFuture.allOf(playerFuture, itemFuture);
all.join();
您可以先开始独立的任务,然后在完成任务后合并步骤。 应该清楚代码在哪个执行器中运行以及在哪里处理异常。
并发不会自动使您的代码变得更快。 必须测量和管理作业大小、延迟、共享状态和执行程序终止。