package banking; import dev.banking.model.BankAccount; import org.junit.jupiter.api.Test; import java.time.Duration; import java.util.concurrent.*; import static org.junit.jupiter.api.Assertions.*; public class BankAccountTransferDeadlockTest { @Test void deadlockFreeTransfers() { assertTimeoutPreemptively(Duration.ofSeconds(5), () -> { BankAccount a = new BankAccount(1, 1_000_000); BankAccount b = new BankAccount(2, 1_000_000); int taskCount = 50_000; ExecutorService executor = Executors.newFixedThreadPool(50); CountDownLatch startGun = new CountDownLatch(1); CountDownLatch finishLine = new CountDownLatch(taskCount * 2); for (int i = 0; i < taskCount; i++) { executor.submit(() -> { try { startGun.await(); a.transfer(b, 1); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } finally { finishLine.countDown(); } }); executor.submit(() -> { try { startGun.await(); b.transfer(a, 1); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } finally { finishLine.countDown(); } }); } startGun.countDown(); boolean completed; try { completed = finishLine.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } executor.shutdown(); assertTrue(completed, "Deadlock detected: tasks did not complete in time"); }); } }