ReentrantLock: почему lock.unlock () не снимает блокировку? - PullRequest
0 голосов
/ 22 июня 2019

Моей задачей было реализовать livelock. Я создал простое приложение. Кажется, работает нормально. Следующей задачей была разработка приложения, которое решило проблему с livelock. Для этого я планирую ввести в свой код переменную со случайным значением. Но сначала я заметил в BankAccount # tryTransfer (...) кое-что неожиданное. Строка кода this.lock.unlock(); (до Thread.sleep(3_000);) не снимает блокировку. Зачем? Любая помощь? Заранее спасибо!

BankAccount.java:

package com.example.livelock;

import java.util.concurrent.locks.*;

public class BankAccount {

    private int id;
    private double balance;
    private Lock lock = new ReentrantLock();

    public BankAccount(int id, double balance) {
        this.id = id;
        this.balance = balance;
    }

    private boolean decreaseMoney(double amount) throws InterruptedException {
        if(lock.tryLock()){
            Thread.sleep(500);
            balance = balance - amount;
            return true;
        }
        return false;
    }

    private boolean increaseMoney(double amount) throws InterruptedException {
        if(lock.tryLock()){
            Thread.sleep(500);
            balance = balance + amount;
            return true;
        }
        return false;
    }

    public void tryTransfer(BankAccount toAccount, double amount) throws InterruptedException {
        while(true){
            if(this.decreaseMoney(amount)){
                if(!toAccount.increaseMoney(amount)){
                    this.increaseMoney(amount);
                    this.lock.unlock();
                    Thread.sleep(3_000);
                    System.out.println(Thread.currentThread().getName() + " is trying to perform transaction, while " + this.lock.toString().replace("java.util.concurrent.locks.", "") + " | " + toAccount.lock.toString().replace("java.util.concurrent.locks.", ""));
                    continue;
                }
                toAccount.unlock();
                this.lock.unlock();
                break;
            }
        }
    }

    public void unlock(){
        lock.unlock();
    }
}

Transaction.java:

package com.example.livelock;

public class Transaction extends Thread {

    private BankAccount fromAccount;
    private BankAccount toAccount;
    private double amount;

    public Transaction(String name, BankAccount fromAccount, BankAccount toAccount, double amount) {
        super(name);
        this.fromAccount = fromAccount;
        this.toAccount = toAccount;
        this.amount = amount;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " has started");
        try {
            fromAccount.tryTransfer(toAccount, 10);
            System.out.println(name + ": money is transfered");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name + " has finished");
    }
}

Tester.java:

package com.example.livelock;

public class Tester {

    public static void main(String[] args) throws InterruptedException {

        String name = Thread. currentThread().getName();
        System.out.println(name + " has started");

        BankAccount account1 = new BankAccount(1, 100);
        BankAccount account2 = new BankAccount(2, 100);

        Transaction th1 = new Transaction("thread-1", account1, account2, 10);
        Transaction th2 = new Transaction("thread-2", account2, account1, 10);

        th1.start();
        th2.start();

        Thread.sleep(30_000);

        System.out.println(name + " has finished");
    }
}
...