对synchronized关键字的理解

先看两个线程同时访问一个对象的例子.

public class Account {
    private String accountNo;
    private double balance;
    public Account() {
    }
    public Account(String accountNo, double balance) {
        this.accountNo = accountNo;
        this.balance = balance;
    }

    public void setAccountNo(String accountNo) {
        this.accountNo = accountNo;
    }
    public String getAccountNo() {
        return this.accountNo;
    }
    public void setBalance(double balance) {
        this.balance = balance;
    }
    public double getBalance() {
        return this.balance;
    }
}
public class DrawThread extends Thread {
    private Account account;
    private double drawAmount;

    public DrawThread(String name, Account account,
                      double drawAmount) {
        super(name);
        this.account = account;
        this.drawAmount = drawAmount;
    }

    @Override
    public void run() {
        if (account.getBalance() >= drawAmount) {
            System.out.println(getName() +
                    "取钱成功!吐出钞票:" + drawAmount);
            account.setBalance(account.getBalance() - drawAmount);
            System.out.println("\t余额为: " + account.getBalance());
        } else {
            System.out.println(getName() + "取钱失败!余额不足!");
        }
    }
}
public class TestDraw {
    public static void main(String[] args) {
        Account acct = new Account("1234567", 1000);
        new DrawThread("甲", acct, 800).start();
        new DrawThread("乙", acct, 800).start();
    }
}

类Account有2个成员变量,帐户名字和余额.DrawThread中的取钱逻辑很简单.先判断余额够不够,如果够,正常取钱,不够的话报余额不足.在TestDraw同时开2个线程取钱,这时候可能会有问题,线程甲判断出还能取钱,准备执行account.setBalance时放弃了处理器,线程乙获得了处理器,判断钱够不够.因为之前线程甲还没有修改balance的值,所以认为可以取钱.所以线程乙取了钱,之后放弃处理器.线程甲之前已经判断过可以取钱,就执行取钱逻辑,这时候帐户余额就变成负的了.多次运行该程序,肯定会出现不正常的现象.
synchronized就是为了解决类似的问题.把DrawThread改成如下形式:

public class DrawThread extends Thread {
    private Account account;
    private double drawAmount;
    public DrawThread(String name, Account account,
                      double drawAmount) {
        super(name);
        this.account = account;
        this.drawAmount = drawAmount;
    }
    @Override
    public void run() {
        synchronized (account) {
            if (account.getBalance() >= drawAmount) {
                System.out.println(getName() +
                        "取钱成功!吐出钞票:" + drawAmount);
                account.setBalance(account.getBalance() - drawAmount);
                System.out.println("\t余额为: " + account.getBalance());
            } else {
                System.out.println(getName() + "取钱失败!余额不足!");
            }
        }
    }
}

synchronized (account){}表示锁住account对象,一个对象访问account时,另外一个对象不能访问.这就保证了线程安全.

posted on   荷楠仁  阅读(164)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义

导航

统计

点击右上角即可分享
微信分享提示