Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么一般不推荐客户端锁定?_Java_Multithreading_Locking_Synchronized - Fatal编程技术网

Java 为什么一般不推荐客户端锁定?

Java 为什么一般不推荐客户端锁定?,java,multithreading,locking,synchronized,Java,Multithreading,Locking,Synchronized,请解释康奈尔州霍茨曼(Hortsmann,Cornell)(第9版,第865页)关于“Core Java”中同步块的以下声明: Vector类的get和set方法是同步的,但这对我们没有帮助。 … 但是,我们可以劫持锁: public void transfer(Vector<Double> accounts, int from, int to, int amount) { synchronized (accounts) { accounts.set(

请解释康奈尔州霍茨曼(Hortsmann,Cornell)(第9版,第865页)关于“Core Java”中同步块的以下声明:

Vector类的get和set方法是同步的,但这对我们没有帮助。

但是,我们可以劫持锁:

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);
    }
    //...
}
public void transfer(向量账户、整数from、整数to、整数金额)
{
已同步(帐户)
{
accounts.set(from,accounts.get(from)-金额);
accounts.set(to,accounts.get(to)+金额);
}
//...
}
这种方法是可行的,但它完全依赖于向量类对其所有mutator方法使用内在锁这一事实

为什么同步依赖于上述事实?如果一根线 拥有帐户上的锁,没有其他线程可以获得相同的锁。它不依赖于向量用于其mutator方法的锁

我能想到的唯一可能的解释是下面的一个。让线程拥有帐户的锁。如果Vector为其set/get使用了另一个锁,那么线程A必须获得一个额外的锁才能继续执行set/get,这是不可能的(一个线程可以同时持有两个不同的锁吗?)

这个解释在我看来似乎不合理,但我没有别的解释。 我错过了什么

如果线程a拥有帐户的锁,那么其他线程都无法获得相同的锁。它不依赖于向量用于其mutator方法的锁

但是如果向量使用了一个完全不相关的锁来进行自己的同步,那么你的锁对象将毫无意义。这样的代码不会同步:

x.transfer(vector, 100, 100, 100);  // uses your lock

vector.add(100);   // uses Vector's own, unrelated lock
如果所有代码都通过自己的方法(使用锁),并且没有人直接访问vector的方法,那么就可以了。(但是您根本不需要使用Vector的内置同步,可以使用ArrayList)

这些锁只有在所有相关代码路径都使用它们时才起作用。通常涉及多个方法,它们需要使用同一组锁正确地“相互交谈”。由程序员来确保这一点。

让线程拥有帐户的锁。如果Vector为其set/get使用了另一个锁,那么线程A必须获得一个额外的锁才能继续执行set/get,这是不可能的(一个线程可以同时持有两个不同的锁吗?)

这不是不可能的,线程A可以持有任意数量的锁。然而,在上面的访问模式中,线程A持有第一个锁是毫无意义的,因为当线程B只使用内置的向量锁时,它甚至不会尝试锁定它

这种方法是可行的,但它完全依赖于向量类对其所有mutator方法使用内在锁这一事实

这试图解释您锁定的是
帐户
,而
向量
锁定的是同一对象。这意味着对
帐户
向量
进行更改的其他线程将被锁定,您将不会有争用条件

如果您没有共享此锁,那么您将有一个竞争条件,因为在该
synchronized
块中有4个操作:

  • 正在从帐户获取当前值
  • 使用递减值设置from帐户
  • 获取帐户的值
  • 使用递增的值将帐户设置为
  • 因为有一个锁,我假设其他线程正在后台修改其他帐户。如果<代码>向量< /代码>假设地改变了它们的内部锁定策略,其他线程可以在这个过程中间对从或到帐户进行更改,并拧紧计费。例如,如果from帐户在#1和#2之间递增,则该值将由于传输而被覆盖

    依赖这样一个类的内部锁定范例是非常糟糕的。这意味着,如果
    Vector
    决定更改其锁定机制(是的,我知道不会),那么您的代码将具有竞争条件。更有可能的情况是,另一个程序员(或未来的您)决定将
    帐户
    更改为不同的
    集合
    ,该集合使用不同的锁定机制,代码将中断。您不应该依赖于类的内部行为,除非它是专门记录的

    如果您需要针对这种竞争条件进行保护,那么您应该对
    向量的
    访问执行
    同步
    锁定


    顺便说一句,你不应该再使用向量了。如果需要同步列表,请使用
    Collections.synchronizedList(新ArrayList)
    或Java 5中引入的一个新并发类。

    我没有读过这本书,但我认为他们想说的是,每个
    向量
    方法都是同步的(独立的),即使这样可以保护
    向量
    不受损坏,也不能保护它可能存储在其中的信息(特别是因为业务规则、数据模型、数据结构设计或您想如何称呼它们)

    示例:方法
    transfer
    是天真地实现的,相信如果它
    Vector
    set
    方法是同步的,那么一切都是好的

    public void transfer(Vector<Double> accounts, int from, int to, int amount) {
        accounts.set(from, accounts.get(from) - amount);
        accounts.set(to, accounts.get(to) + amount);
    }
    
    public void transfer(向量账户、整数from、整数to、整数金额){
    accounts.set(from,accounts.get(from)-金额);
    accounts.set(to,accounts.get(to)+金额);
    }
    
    如果两个线程(T2和T3)同时调用
    传输
    ,例如,从余额为1500美元的
    账户(A1)调用相同的
    ,并将不同的
    传输到余额为0美元的
    账户(A2和A3)?例如100美元到A2,1200美元到A3

  • T2:
    accounts.get('A1')
    被检索并减去100。