经典的同步问题(银行取钱)

本文通过一个银行取款的例子展示了同步的重要性。在多线程环境下,如果不使用同步机制,可能会导致账户余额出现负数等异常情况。通过使用synchronized关键字,可以确保每次只有一个线程能访问账户余额,从而避免了此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

银行取钱问题是非常经典的同步问题,如果不采用同步方法,可能也不会发生错误,但就是那小概率事件就可以称之为BUG吧。
没有使用同步方法的代码如下:

public class ErrorTest{
    public static void main(String[] args)
    {
        user ur = new user(1000,"账户");
        new errorThread(800,"甲",ur).start();
        new errorThread(800,"乙",ur).start();
    }       
}
class user
{
    private int balance;
    private String name;
    public user(int balance,String name)
    {
        this.balance = balance;
        this.name = name;
    }
    public int getBalance() {
        return balance;
    }
    public void setBalance(int balance) {
        this.balance = balance;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public int hashCode()
    {
        return name.hashCode();
    }
    @Override
    public boolean equals(Object o)
    {
        if (o == this)
        {
            return true;
        }
        if (o.getClass() == user.class && o !=null )
        {
            user ur = (user)o;
            if (ur.name.equals(name))
            {
                return true;
            }
        }
        return false;
    }   
}
class errorThread extends Thread
{
    private int money;
    //private String name;
    private user ur;
    public errorThread(int money,String name,user ur)
    {
        super(name);
        this.money = money;
        this.ur = ur;
    }
    @Override
    public void run()
    {

            if (ur.getBalance() >= money)
            {
                System.out.println(getName()+"成功取出钞票"+money);
                ur.setBalance(ur.getBalance()-money);
                System.out.println("剩下的钱:"+ur.getBalance());
                try{
                    sleep(10);//这里用了sleep(),强制线程切换
                }catch(InterruptedException ie)
                {
                    ie.printStackTrace();
                }
            }

            else
            {
                System.out.println(getName()+"余额不足,取钱失败");
            }

    }
}

运行你结果如下:
甲成功取出钞票800
乙成功取出钞票800
剩下的钱:200
剩下的钱:-600
这样银行岂不会陪哭了?哈哈哈哈。
因此,必须使用同步方法,通常情况下使用被并发访问的共享资源作为同步监视器,代码如下:

public class ErrorTest{
    public static void main(String[] args)
    {
        user ur = new user(1000,"账户");
        new errorThread(800,"甲",ur).start();
        new errorThread(800,"乙",ur).start();
    }       
}
class user
{
    private int balance;
    private String name;
    public user(int balance,String name)
    {
        this.balance = balance;
        this.name = name;
    }
    public int getBalance() {
        return balance;
    }
    public void setBalance(int balance) {
        this.balance = balance;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public int hashCode()
    {
        return name.hashCode();
    }
    @Override
    public boolean equals(Object o)
    {
        if (o == this)
        {
            return true;
        }
        if (o.getClass() == user.class && o !=null )
        {
            user ur = (user)o;
            if (ur.name.equals(name))
            {
                return true;
            }
        }
        return false;
    }   
}
class errorThread extends Thread
{
    private int money;
    //private String name;
    private user ur;
    public errorThread(int money,String name,user ur)
    {
        super(name);
        this.money = money;
        this.ur = ur;
    }
    @Override
    public void run()
    {
        synchronized(ur)
        {
            if (ur.getBalance() >= money)

            {
                System.out.println(getName()+"成功取出钞票"+money);
                ur.setBalance(ur.getBalance()-money);
                System.out.println("剩下的钱:"+ur.getBalance());
                try{
                    sleep(10);
                }catch(InterruptedException ie)
                {
                    ie.printStackTrace();
                }
            }

            else
            {
                System.out.println(getName()+"余额不足,取钱失败");
            }
        }
    }
}

运行结果如下:
甲成功取出钞票800
剩下的钱:200
乙余额不足,取钱失败
这样符合”加锁-修改-释放锁“的逻辑,银行再也不用担心亏钱了,嘻嘻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

helloworddm

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值