我一直在研究编写具有多个线程访问共享变量的应用程序,因为我即将编写第一个使用多个线程的应用程序!我想我理解使用多个线程的风险,但我不确定什么是我的场景的最佳方法。在我的应用程序中,我只有一个将由多个线程访问的对象。我希望它看起来像这样:
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类中的所有函数都是同步的,这是否会被认为是安全的,或者两个尝试调用同一对象上的函数的线程是否仍会导致问题发生?
我应该使用其他方法,这会让我更容易吗?指向我可以帮助我的任何教程或文档也很棒!
提前感谢您的帮助!
答案 0 :(得分:0)
如果您在Java教程中阅读Atomic Access,您将看到String和字节数组的赋值可以被认为是原子的,因为它们是引用变量。
- 读取和写入对于参考变量是原子的和大多数原始变量(除了long和double之外的所有类型)。
- 读取和写入对于所有声明为volatile的变量都是原子的(包括长变量和双变量)。
然后句子String newValue1 = connector.getValue1()
没有问题,因为一旦连接器返回String,它将是一致的,而且字符串是不可变的,Connector
永远不会改变值。
问题更多是connector.getValue2()
,因为后续调用中的连接器可能会修改该数组。即使在单线程应用程序中,这也很危险。然后你必须确保连接器一旦返回就不会修改数组(可能在getter中返回一个副本)
需要线程安全的是Connector
本身,如果不是,则无法安全地在线程之间共享它们,在这种情况下通过SharedObj
。