Cristian
Cristian

Reputation: 285

java threads and mutual exclusion

I have the following classes to represent a banking system:

The class that is a monitor: BankAccount

public class BankAccount 
{
    private boolean isLocked = false;
    private int balance;
    private String name;
    private int nrWithdrawals;
    public  Transaction Transaction;

    public BankAccount()
    {
        this.balance = 300;
        this.name = "Bank Account";
    }

    public synchronized void  withdraw(Transaction tran)
    {
        while(!canWithdraw(tran))
        {
            try
            {  
                wait();
                System.out.println("Not enough money: ");                               
            }
            catch( InterruptedException e) {}
        }

        this.setBalance((this.getBalance() - tran.getBalance()));
        System.out.println("Remaining Balance is: " + this.getBalance());
    }


    public synchronized void depositMoney( )
    {
        while(this.getBalance() + 100 <= this.BankAccountLimit)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e){}
        }

        this.setBalance(this.getBalance() + 100);
        System.out.println("Bank Account balance is: " + this.getBalance());
    }
}

A class(thread) called: User

public class User extends Thread
{   
    private final BankAccount account;
    private ThreadGroup threadGroup;
    private Transaction tran;
    private String bName;
    private String userName;

    public User(BankAccount acc, ThreadGroup group, String name)
    {
        super(group, name);
        this.account = acc
        this.userName = name;
        this.threadGroup = group;
    }

    public void run()
    {
        for(int i = 0; i< 3; i++)
        {
            Transaction transaction = new Transaction(70);
            account.withdraw(tran);

            System.out.println(this.getUserName() + " is using the bankaccount");
            try
            {  
                sleep(2000);     
            }
            catch(InterruptedException e){}
        } 
    }
}

A class(thread) called Manager

public class Manager extends Thread
{
    private final BankAccount account;
    private ThreadGroup threadGroup;
    private String managerName;

    public Manager(BankAccount acc, ThreadGroup tgroup, String name)
    {
        account = acc;
        threadGroup = tgroup;
        managerName = name;
    }

    public void run()
    {
        for(int i = 0; i < 3; i++)
        {
            account.depositMoney();
            try
            {
                sleep(100);
                System.out.println("trying....");
            }
        }
        catch(InterruptedException e){} 
    }  
}

and a main method

public static void main(String[] args) 
{
    ThreadGroup users = new ThreadGroup("Users");
    ThreadGroup managers = new ThreadGroup("Managers");

    BankAccount account = new BankAccount();
    User user1 = new User(account, users, "User1");
    User user2 = new User(account, users, "User2");
    Manager manager = new Manager(account, managers, "Manager1");   
    user1.start();
    user2.start();
    manager.start();
}

What I would like to achieve would be something like this:

user1 or user2 start withdrawing money(each one try for a number of times). Lets say user1 starts first.

If there is not enough money wait until the manager deposits(tries to deposit three times or something likethis) some money and afterwards user1 resumes withdrawing money then after he finishes user2 starts withdrawing money.

The issues I have: How do I make sure that either user1 or user2 is the first thread to run. Is it posible make a thread wait, execute another and resume the one that is waiting ?(make user1 wait, execute manager then resume user1 and then execute the remaining user?)

Upvotes: 0

Views: 1044

Answers (2)

Eranda
Eranda

Reputation: 1467

There are few mistakes you have done here.

  1. Your balance is not thread safe. Two threads can alter it within Withdraw and depositMoney methods. So you can use a mutex, ReenterantLock as bot explained.
  2. If your execution ended up in wait(), either Withdraw or depositMoney then there is no way of getting out of it. To avoid that you can call notifyAll() after each withdraw or deposit.

Here is the sample code with the suggested alterations

public class BankAccount
    {
        private boolean isLocked = false;
        private int balance;
        private String name;
        private int nrWithdrawals;
        public  Transaction Transaction;
        private ReentrantLock lock = new ReentrantLock();

        public BankAccount()
        {
            this.balance = 300;
            this.name = "Bank Account";
        }

        public synchronized void Withdraw(Transaction tran)
        {
            lock.lock();
            while(!CanWithdraw(tran))
            {
                try
                {
                    lock.unlock();
                    System.out.println("Not enough money. Waiting for manager to deposit");
                    wait();
                    lock.lock();

                }
                catch( InterruptedException e) {}
            }
            this.setBalance((this.getBalance() - tran.getBalance()));
            notifyAll();

            System.out.println("Remaining Balance is: " + this.getBalance());
            lock.unlock();
        }


        public synchronized void depositMoney( )
        {
            lock.lock();
            while(this.getBalance() + 100 <= this.BankAccountLimit)
            {
                try
                {
                    lock.unlock();
                    wait();
                    lock.lock();
                }
                catch(InterruptedException e){}
            }


            this.setBalance(this.getBalance() + 100);
            notifyAll();
            System.out.println("Bank Account balance is: " + this.getBalance());
            lock.unlock();
        }
    }

Upvotes: 1

Chetan Kinger
Chetan Kinger

Reputation: 15212

Is it posible make a thread wait, execute another and resume the one that is waiting

Yes. What you are referring to is a classic case of the producer-consumer problem.

You can use explicit synchronization by using the synchronized keyword. Use the wait method to make a thread release it's locks and use the notify method to notify threads that the lock is now available.

You can also use a ReenterantLock

Upvotes: 2

Related Questions