Java from Basics to Mastery — Part 8
Safely executing threads and asynchronous operations
The articles written on this blog were created with the goal of teaching. Also, the information in the article may be incorrect, so please be careful.
Running multiple tasks simultaneously can increase throughput, but also increases the complexity of shared state. Before deciding on the number of threads, you need to decide who will change the state and how to communicate completion and failure.
ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(4);
try {
Future<Integer> result = executor.submit(() -> loadScore());
int score = result.get();
System.out.println(score);
} finally {
executor.shutdown();
}
When a task is submitted to ExecutorService, the executor manages thread creation and reuse. Future's get makes the current thread wait until completion and also throws a task exception.
Protecting shared state
private final Object lock = new Object();
private int gold;
public void addGold(int amount) {
synchronized (lock) {
gold += amount;
}
}
If multiple threads read and write the same value simultaneously, operations may be lost or intermediate states may appear. synchronized allows only one thread to execute sections that use the same lock at a time.
If the lock range is too wide, waiting increases, and acquiring multiple locks in different orders can lead to deadlock. If possible, it is better to reduce the mutable shared state itself.
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();
You can start independent tasks first and combine the steps after completing them. It should be clear in which executor the code runs and where exceptions are handled.
Concurrency does not automatically make your code faster. Job size, latency, shared state, and executor termination must be measured and managed.