对Java核心技术中一段关于线程同步的代码的疑问

发布于 2022-09-02 11:29:21 字数 926 浏览 42 评论 0

《Java核心技术第九版 卷I》的14.5.6 Synchronized Blocks一节有一段代码:

public void transfer(Vector<Double> accounts, int from, int to, int amount) {
    synchronized (accounts) {
        accounts.set(from, accounts.get(from) - amount);
        accounts.set(to, accounts.get(to) + amount);
    }
    System.out.println(. . .);
}

这段代码是模拟银行转账的,当多个线程并发地进行转账时,如果不进行同步就会导致账户中的数据出现不一致的情况。所以书里给这段代码加了synchronized同步。

但是书中这段程序后面还有一句话:

This approach works, but it is entirely dependent on the fact that the Vector class uses the intrinsic lock for all of its mutator methods.

(加了同步之后)这就没问题了,但是这段代码完全依赖于Vector类是否使用它自己的锁来同步它的修改方法。

问题来了,为什么这样写还要依赖于Vector是否加锁,以及加锁方式呢?我认为不管Vector是否是同步的这段代码都没问题。我实际测试了,将Vector换成非同步的ArrayList,确实没有任何问题!不知道作者为什么这样说,难道是我哪里理解的不对?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感性 2022-09-09 11:29:21

这句话大概是指 synchronized (accounts)Vector中方法的 intrinsic lock(锁this) 使用的锁都是实例对象本身,所以这种写法才有效,要保证使用同一个锁。

假设有两个不同的线程类A和B,都持有 accounts 的引用,线程类A启动的线程使用synchronized (accounts) 加锁进行同步,而线程类B启动的线程没有,直接使用 accounts.set 方法进行修改。

如果使用 Vector 类,A线程锁了 accounts 对象,B中调用 set 方法时,由于 set 方法使用synchronized 修饰,B也需要获取 this,即:accounts 对象的锁,才能修改,A线程释放锁之前B线程是无法执行的。

如果使用 ArrayList 类,B不需要获取锁,直接可以进行修改,会导致状态不一致。

极度宠爱 2022-09-09 11:29:21

accounts参数是通过方法调用传进来的,很难保证在进行方法调用之前,程序将accounts对象发布到了其他线程,这样就有可能有其它线程修改他了。所以作者说依赖于Vector类的同步机制。比如:

doTransfer() {
    final Vector<Double> accounts = ...
    new Thread(() -> {
        //更改accounts并且没有进行同步
    }).start()
    //调用transfer
    transfer(accounts .......)
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文