有一個賽跑比賽,4個人參賽,給前三名頒發得金銀銅牌,用代碼怎么寫呢
//運動員
@Data
@RequiredArgsConstructor
public static class Runner {
private final String name;
private Integer score;
}
// 頒獎類
public static class AwardUtils {
private static BlockingQueue<String> awardQueue = new LinkedBlockingQueue<>(3);
static {
awardQueue.offer("金牌");
awardQueue.offer("銀牌");
awardQueue.offer("銅牌");
}
public static void winAward(String name) {
String award = awardQueue.poll();
if (award != null) {
log.info("{} 獲得了 {}", name, award);
} else {
log.info("{} 沒有獲得獎牌", name);
}
}
}
普通做法:我們可以等運動員跑玩,看誰用時少來頒獎
CountDownLatch countDownLatch = new CountDownLatch(1);
// 賽跑任務
Function<Runner, Callable<Runner>> runTask = (runner) -> () -> {
countDownLatch.await();
int time = ThreadLocalRandom.current().nextInt(10, 20);
runner.setScore(time);
TimeUnit.SECONDS.sleep(time);
log.info("{} 跑了 {} 秒", runner.getName(), time);
return runner;
};
ExecutorService executor = Executors.newFixedThreadPool(4);
List<Future<Runner>> results = Arrays.asList(
executor.submit(runTask.Apply(new Runner("小明"))),
executor.submit(runTask.apply(new Runner("小鵬"))),
executor.submit(runTask.apply(new Runner("小張"))),
executor.submit(runTask.apply(new Runner("小李")))
);
countDownLatch.countDown();
results.stream().map(future -> {
try {
return future.get(20, TimeUnit.SECONDS);
} catch (TimeoutException | InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}).sorted((runner1, runner2) -> {
int score1 = runner1.getScore();
int score2 = runner2.getScore();
return Integer.compare(score1, score2);
}).forEach(runner -> {
AwardUtils.winAward(runner.getName());
});
11:21:38,915 [pool-1-thread-2] INFO - 小鵬 跑了 11 秒
11:21:42,908 [pool-1-thread-4] INFO - 小李 跑了 15 秒
11:21:43,901 [pool-1-thread-3] INFO - 小張 跑了 16 秒
11:21:43,901 [pool-1-thread-1] INFO - 小明 跑了 16 秒
11:21:43,902 [main] INFO - 小鵬 獲得了 金牌
11:21:43,902 [main] INFO - 小李 獲得了 銀牌
11:21:43,902 [main] INFO - 小明 獲得了 銅牌
11:21:43,902 [main] INFO - 小張 沒有獲得獎牌
CompletionService:有人跑完了就把獎牌給他,不用等其他人是否跑完
主要功能就是一邊執行任務,一邊獲取任務的返回值。讓兩件事分開執行,任務之間不會互相阻塞,可以實現先執行完的先取結果,不依賴任務順序
CountDownLatch countDownLatch = new CountDownLatch(1);
Function<Runner, Callable<Runner>> runTask = (runner) -> () -> {
countDownLatch.await();
int time = ThreadLocalRandom.current().nextInt(10, 20);
runner.setScore(time);
TimeUnit.SECONDS.sleep(time);
log.info("{} 跑了 {} 秒", runner.getName(), time);
return runner;
};
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletionService<Runner> completionService = new ExecutorCompletionService<>(executor);
completionService.submit(runTask.apply(new Runner("小明")));
completionService.submit(runTask.apply(new Runner("小鵬")));
completionService.submit(runTask.apply(new Runner("小張")));
completionService.submit(runTask.apply(new Runner("小李")));
countDownLatch.countDown();
for (int i = 0; i < 4; i++) {
AwardUtils.winAward(completionService.take().get().getName());
}
11:11:15,125 [pool-1-thread-3] INFO - 小張 跑了 10 秒
11:11:15,130 [main] INFO - 小張 獲得了 金牌
11:11:19,122 [pool-1-thread-1] INFO - 小明 跑了 14 秒
11:11:19,122 [main] INFO - 小明 獲得了 銀牌
11:11:20,125 [pool-1-thread-4] INFO - 小李 跑了 15 秒
11:11:20,125 [main] INFO - 小李 獲得了 銅牌
11:11:22,132 [pool-1-thread-2] - 小鵬 跑了 17 秒
11:11:22,132 [main] INFO - 小鵬 沒有獲得獎牌
ExecutorCompletionService 類中維護一個了 BlockingQueue;
public class ExecutorCompletionService<V> implements CompletionService<V> {
private final BlockingQueue<Future<V>> completionQueue;
public Future<V> submit(Callable<V> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<V> f = newTaskFor(task);
executor.execute(new QueueingFuture(f));
return f;
}
}
QueueingFuture 重寫了done 方法 ,done 方法會在完成或取消任務時執行,將其加入隊列
private class QueueingFuture extends FutureTask<Void> {
QueueingFuture(RunnableFuture<V> task) {
super(task, null);
this.task = task;
}
protected void done() { completionQueue.add(task); }
private final Future<V> task;
}