![](/img/trans.png)
[英]A question about the **Type Erasure mechanism** when read the Core Java 11th ed
[英]CoreJava 11th Ed Threading question on client-side locking (synchronized block)
我正在阅读以下关于为什么不建议使用客户端锁定的部分,如下所示:
“有时,程序员使用对象的锁来实现额外的
原子操作——一种称为客户端锁定的实践。 考虑,对于
例如,Vector 类,它是一个方法同步的列表。
现在假设我们将银行余额存储在 Vector 中。 这是
传输方法的简单实现:
public void transfer(向量账户,int from,int to,int amount)//
{
account.set(from,accounts.get(from) - 金额);
account.set(to, accounts.get(to) + amount);
System.out.println(. . .);
}
Vector 类的 get 和 set 方法是同步的,但是
对我们没有帮助。 线程被抢占是完全有可能的
在第一次调用 get 完成后的 transfer 方法。 其他
然后线程可以将不同的值存储到相同的位置。 然而,我们
可以劫持锁:
公共无效转移(矢量帐户,int from,int to,int金额)
{
同步(帐户)
{
account.set(from,accounts.get(from) - 金额);
account.set(to, accounts.get(to) + amount);
}
System.out.println(. . .);
}
这种方法有效,但它完全取决于 Vector
class 对其所有的 mutator 方法使用内在锁。 然而,这是
真的是事实吗? Vector 类的文档没有这样的
承诺。 你要仔细研究源代码,希望以后
版本不会引入不同步的变异器。 如您所见,客户-
侧锁非常脆弱,一般不推荐使用。”
问题:
既然transfer方法中的synchronized(accounts)已经获得了accounts内在锁,那么为什么依赖vector类的所有mutator方法都使用内在锁(如粗斜体突出显示的?
如果accounts
Vector
的唯一突变发生在transfer
方法中,那么Vector
同步其突变器就无关紧要了。
但是,通过锁定相同的对象已有的突变方法(即对Vector
),我们防止对其他任何不同诱变操作Vector
。
这不仅仅是由另一个线程完成的可能破坏我们数据的传输,而是例如,在我们读取余额之后和设置之前在to
帐户上执行的存款。
正如 Holger 指出的那样,一旦你在一个线程中发生了变化并在另一个线程中读取,如果你想要数据的一致视图,甚至读取操作也需要同步。
正如Core Java所建议的那样,最好封装您要保护的数据,例如(玩具示例)
public class Accounts {
private final List<Integer> accounts = new ArrayList();
public synchronized void transfer(int from, int to, int amount) {
accounts.set(from, accounts.get(from) - amount);
accounts.set(to, accounts.get(to) + amount);
}
public synchronized void deposit(int to, int amount) {
accounts.set(to, accounts.get(to) + amount);
}
public synchronized List<Integer> getAccountsSnapshot() {
// don't return our internal data structure, make a defensive copy
return new ArrayList(accounts);
}
}
返回数据的副本执行两个功能:
ArrayList
的值,而无需使用我们提供的 API。getAccountsSnapshot
时有效的总数。 否则,他们在计算总和时的修改可能意味着他们得到了“现实生活”中从未发生过的总和。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.