在java中同步线程的问题

时间:2018-01-17 22:27:49

标签: java synchronization synchronized

我试图编写一个示例程序,其中包含可以修改金额的银行帐户对象,以及从2个不同的银行帐户中移动1个单位货币100万次的10个从属对象对象。我的预期结果是银行账户货币的总和在最后为0,就像我开始时一样。我已经尝试过同步" setBalance" BankAccount中的方法,因为我认为这是应该同步的方法,但这并不起作用。当我在getBalance上尝试它或者即使那些也没有工作时,我也不确定我做错了什么。

BankAccount.java

public class BankAccount{

    private int balance;

    public BankAccount()
    {
        balance = 0;
    }

    public int getBalance()
    {
        return balance;
    }

    public void setBalance(int balance)
    {
        this.balance = balance;
    }
}

Slave.java

public class Slave extends Thread {

    BankAccount source;
    BankAccount target;

    int currency = 1;

    public Slave (BankAccount source, BankAccount target) {
        this.source = source;
        this.target = target;

    }

    public void run() {
        for (int i = 0; i < 1000000; i++)
        {
            target.setBalance(target.getBalance() + currency);
            source.setBalance(source.getBalance() - currency);
        }
    }
}

Master.java

public class Master {

    public static void main(String[] args) {

        BankAccount account1 = new BankAccount();
        BankAccount account2 = new BankAccount();

        Slave[] slaves = new Slave[10];

        for (int i = 0; i < 10; i++)
        {
            if (i < 5)
            {
                slaves[i] = new Slave(account1, account2);
            }
            else
            {
                slaves[i] = new Slave(account2, account1);
            }
        }

        for (int i = 0; i < 10; i++)
        {
            slaves[i].start();
        }

        try
        {
            for (Slave s : slaves)
                s.join();
        }
        catch (InterruptedException e) {
            System.out.println("Interruption before completion of the joins" + e);
        }


        System.out.println("Sum of balances: " + (account1.getBalance() + account2.getBalance()));
    }
}

2 个答案:

答案 0 :(得分:1)

synchronized关键字(如果在方法签名中使用)会对要调用的对象进行锁定。如果您希望锁定备用对象,则需要以这种方式使用关键字:

synchronized(objectToLock) {
    doAtomicStuff();
}

在您的情况下,您的原子操作正在获取,调整和设置余额,您将需要锁定相关的BankAccount对象。

这应该足以让您找出使用synchronized的地点和方式。

答案 1 :(得分:0)

此代码......

            target.setBalance(target.getBalance() + currency);
只有在target的{​​{1}}调用与getBalance()的调用之间不同的线程修改setBalance()的余额时,

...才会在线程T1中产生预期效果。同步这些方法中的一个或两个并不能阻止这种干预修改,并且您的多个线程正在执行如此多的线程,如此之快,以至于您很可能会遇到这个问题。

因此,适当的关键区域包含两个方法调用,您可以通过将它们放在synchronized块中来实现:

            synchronized(target) {
                target.setBalance(target.getBalance() + currency);
            }

当然,您需要同样处理source的更新。请注意,对于每个关键区域,所有竞争线程需要在同一对象上进行同步,以使同步具有所需的效果。