可能长时间延迟的多线程

时间:2014-02-22 09:23:00

标签: java multithreading thread-safety

我一直在研究编写具有多个线程访问共享变量的应用程序,因为我即将编写第一个使用多个线程的应用程序!我想我理解使用多个线程的风险,但我不确定什么是我的场景的最佳方法。在我的应用程序中,我只有一个将由多个线程访问的对象。我希望它看起来像这样:

public class SharedObj {
    // Variables shared by all threads
    private String value1;
    private byte[] value2;
    // A connector which maintains a tcp connection and handles transactions with a server
    // It is used to update 'value1' and 'value2' with there values on the server
    private Connector connector;

    public void update() {
        String newValue1 = connector.getValue1();
        synchronized(this) {
            value1 = newValue1;
        }
        byte[] newValue2 = connector.getValue2();
        synchronized(this) {
            value2 = newValue2;
        }
    }

    public void setValue1(String newValue) {
        if(connector.updateValue1(newValue)) {
            synchronized(this) {
                value1 = newValue;
            }
        }
    }
    public String getValue1() {
        String ret;
        synchronized(this) {
            ret = value1;
        }
        return ret;
    }
}

我认为解决这个问题的一个简单方法是使每个函数同步,但是当调用update()时,对象可能会被锁定很长一段时间,因为字节数组实际上可以是任意大小,因此需要很长时间才能通过网络传输。这就是为什么我只想在读取或更改变量时锁定对象,以便它们可以在没有长时间延迟的情况下保持可访问状态。我不在乎setValue1()update()是否会被长时间阻止,但getValue1()功能无法长时间阻止。

现在回到上面的例子。假设我的Connector类中的所有函数都是同步的。如果是这种情况,上述例子会被认为是安全的吗?我的困惑在于同步是如何工作的。我关心的是update()可以被一个线程调用,当另一个线程调用函数String newValue1 = connector.getValue1()并且连接器对象用于调用另一个线程时,它位于行setValue1("something")的中间位置功能。由于Connector类中的所有函数都是同步的,这是否会被认为是安全的,或者两个尝试调用同一对象上的函数的线程是否仍会导致问题发生?

我应该使用其他方法,这会让我更容易吗?指向我可以帮助我的任何教程或文档也很棒!

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

如果您在Java教程中阅读Atomic Access,您将看到String和字节数组的赋值可以被认为是原子的,因为它们是引用变量。

  
      
  • 读取和写入对于参考变量是原子的和大多数原始变量(除了long和double之外的所有类型)。
  •   
  • 读取和写入对于所有声明为volatile的变量都是原子的(包括长变量和双变量)。
  •   

然后句子String newValue1 = connector.getValue1()没有问题,因为一旦连接器返回String,它将是一致的,而且字符串是不可变的,Connector永远不会改变值。

问题更多是connector.getValue2(),因为后续调用中的连接器可能会修改该数组。即使在单线程应用程序中,这也很危险。然后你必须确保连接器一旦返回就不会修改数组(可能在getter中返回一个副本)

需要线程安全的是Connector本身,如果不是,则无法安全地在线程之间共享它们,在这种情况下通过SharedObj