В чем разница между кодом, который вызывает тупик, и кодом, который его предотвращает?Нужно объяснение для примера кода - PullRequest
0 голосов
/ 25 января 2019

Мне дан код примера банковской деятельности, и я пытаюсь выяснить, вызывает ли это тупик или нет. Если так, то какая часть кода достигает этого? Я также хотел бы знать, как я изменил бы код, чтобы предотвратить взаимные блокировки. Я знаю, что это как-то связано с упорядочением методов, но этот код меня смущает. Я новичок в сетевом программировании, поэтому я все еще немного запутался в этой теме.

Я написал это на Java.

банк публичного класса {

public Bank(int n, double initialBalance)
{
    accounts = new double[n];
    Arrays.fill(accounts, initialBalance);
    bankLock = new ReentrantLock();
    sufficientFunds = bankLock.newCondition();
}

public synchronized void transfer(int from, int to, double amount) throws InterruptedException
{
     bankLock.lock();
     try
     {
        while (accounts[from] < amount)
           sufficientFunds.await();
        System.out.print(Thread.currentThread());
        accounts[from] -= amount;
        System.out.printf(" %10.2f from %d to %d", amount, from, to);
        accounts[to] += amount;
        System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
        sufficientFunds.signalAll();
     }
     finally
     {
        bankLock.unlock();
     }
}

public synchronized double getTotalBalance()
{
    bankLock.lock();
     try
     {
        double sum = 0;

        for (double a : accounts)
           sum += a;

        return sum;
     }
     finally
     {
        bankLock.unlock();
     }
}

public int size()
{
    return accounts.length;
}

публичный класс DeadlockApp {

public static void main(String[] args) 
{
    Bank bank = new Bank(NACCOUNTS,INITIAL_BALANCE);
    for (int i = 0; i< NACCOUNTS; i++)
    {
        int fromAccount = i;
        Runnable r = () -> 
        {
            try 
            {
                while (true) 
                {
                    int toAccount = (int) (bank.size() * Math.random());
                    double amount = MAX_AMOUNT * Math.random();
                    bank.transfer(fromAccount, toAccount, amount);
                    Thread.sleep((int)(DELAY * Math.random()));
                }
            }
            catch (InterruptedException e)
            {
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

Когда я запускал код, он был очень медленным и давал только два результата, поэтому я не мог определить, был ли это тупик, который продолжался непрерывно, или моя IDE просто отставала.

1 Ответ

0 голосов
/ 25 января 2019

Основным требованием для взаимоблокировки является то, что два или более потоков пытаются получить серию блокировок, но приобретают их в различном порядке.

У вас есть две блокировки в игре, но все потоки выполняют одну и ту жекод, который имеет фиксированный порядок получения блокировки, и обе блокировки могут быть получены рекурсивно, поэтому нет тупиков.

Точнее говоря, в transfer одновременно выполняется только один поток, поскольку synchronized.

Блокировки получаются в следующем порядке:

  1. Монитор банка («синхронизирован» при переводе)
  2. banklock (в переводе)
  3. Монитор банка снова («синхронизирован» по getTotalBalance) - но мы его уже держим, поэтому онне будет блокировать
  4. banklock (в getTotalBalance), но мы уже удерживаем его, чтобы он не блокировал

Нет тупиков, поэтому есть и другие причины для «медлительности».Я предполагаю, сколько времени займет случайное действие, чтобы собрать достаточно средств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...