#264 Deadlock при переводе между кошельками

Компании:
Т-Банк
Темы:
JavaМногопоточностьКод ревью

Что будет напечатано? Сделать код-ревью:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        /*
         * Каждый кошелек характеризуется одним intом - балансом.
         * Изначально создаем список из 10 кошельков, на каждом из которых баланс равен 100.
         */
        List<Wallet> wallets = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            wallets.add(new Wallet(100));
        }

        ExecutorService executor = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 100000; i++) {
            /*
             * Переводим все деньги с одного кошелька на другой.
             * Для каждого перевода выбираются последовательные кошельки:
             * из 1 всегда переводим во 2, из 2 всегда переводим в 3 и т.д.
             * из последнего кошелька всегда переводим в первый.
             */
            Wallet wallet1 = wallets.get(i % wallets.size());
            Wallet wallet2 = wallets.get((i + 1) % wallets.size());
            executor.execute(() -> transfer(wallet1, wallet2));
        }

        executor.shutdown(); // Не отменяет уже засабмиченные таски
        executor.awaitTermination(1, TimeUnit.DAYS); // Дожидается исполнения всех засабмиченных тасок

        /*
         * Здесь считаем сумму балансов всех кошельков и выводим её.
         * Если бы предыдущего цикла не было, то ожидается, что выведется 1000
         * (потому что изначально было 10 кошельков по 100 монет).
         */
        int sum = wallets.stream().mapToInt(wallet -> wallet.balance).sum();
        System.out.println(sum);
    }

    private static void transfer(Wallet wallet1, Wallet wallet2) {
        synchronized (wallet1) {
            synchronized (wallet2) {
                wallet2.balance += wallet1.balance;
                wallet1.balance = 0;
            }
        }
    }

    private static class Wallet {
        public int balance;

        public Wallet(int balance) {
            this.balance = balance;
        }
    }
}

Разбор вопроса

Ментор
Ответь как на реальном собеседовании. Я задам уточняющие вопросы, а затем сравню твой ответ с эталонным и покажу точность в %.
Войди, чтобы начать диалог Ментор ведёт диалог по текущему вопросу и учитывает предыдущие сообщения.
Войти