1

我有一个类似于以下的静态类数组:

public class Entry {
    private String sharedvariable1= "";
    private String sharedvariable2= "";
    private int sharedvariable3= -1;

    private int mutablevariable1 = -1
    private int mutablevariable2 = -2;

    public Entry (String sharedvariable1, 
                  String sharedvariable2, 
                  int sharedvariable3) {
        this.sharedvariable1 = sharedvariable1;
        this.sharedvariable2 = sharedvariable2;
        this.sharedvariable3 = sharedvariable 3;
    }

    public Entry (Entry entry) {  //copy constructor. 
        this (entry.getSharedvariable1, 
              entry.getSharedvariable2, 
              entry.getSharedvaraible3);
    }
....
/* other methods including getters and setters*/
}

在我的程序中的某个时刻,我访问了该对象的一个​​实例,并使用上面的复制构造函数对其进行了复制。然后我更改上面两个可变变量的值。该程序在多线程环境中运行。 请注意。所有变量在穿线前都设置了它们的初始值。 只有在程序被线程化并复制后,变量才会改变。我相信它是线程安全的,因为我只读取静态对象,而不是写入它(即使是共享变量 3,尽管只读取 int 和可变对象)并且我只更改静态对象的副本(以及正在一个线程中制作副本)。但是,我想在这里确认我的想法是正确的。

有人可以评估我在做什么吗?

4

5 回答 5

3

它不是线程安全的。您需要包装任何修改共享变量的内容:

synchronized (this) {
    this.sharedvariable1 = newValue;
}

对于二传手,您可以这样做:

public synchronized void setSharedvariable1(String sharedvariable1) {
    this.sharedvariable1 = sharedvariable1;
}

然后在你的复制构造函数中,你会做类似的事情:

public Entry (Entry entry) {
    this();
    synchronized(entry) {
        this.setSharedvariable1(entry.getSharedvariable1());
        this.setSharedvariable2(entry.getSharedvariable2());
        this.setSharedvariable3(entry.getSharedvariable3());
    }
}

这确保了如果正在对实例进行修改,则复制操作将等到修改完成。

于 2012-04-17T12:48:58.260 回答
0

它不是线程安全的,您应该在复制构造函数中同步。您正在从复制构造函数中的原始对象读取三个变量中的每一个。这些操作一起不是原子的。因此,当您读取第一个值时,可能是第三个值被另一个线程更改。在这种情况下,您有一个处于不一致状态的“复制”对象。

于 2012-04-17T12:47:27.653 回答
0

它不是线程安全的。我的意思是这并不能保证Entry使用同一实例的多个线程的线程安全。

我在这里看到的问题如下:

  1. Thread 1开始构建Entry实例。它不会使该实例对其他线程的访问隐藏。
  2. Thread 2使用它的复制构造函数访问该实例,而它仍在构造的中间。

Entry考虑到的 field的初始值private int sharedvariable3= -1;,结果可能是由创建的新“复制”实例Thread 2将其sharedvariable3字段设置为0(java 中 int 类字段的默认值)。

那就是问题所在。

如果它困扰您,您必须进行synchronize读/写操作,或处理Entry实例发布。意思是,不允许其他线程访问Entry正在构建的实例。

于 2012-04-17T13:07:50.467 回答
0

我真的不明白,为什么你认为私有实例变量是共享的。通常共享字段是静态的而不是私有的——我建议您不要共享私有实例变量。为了线程安全,您应该同步改变变量值的操作。

您可以为此使用 synchronized 关键字,但要选择正确的监视器对象(我认为条目本身应该这样做)。另一种选择是使用 java.util.concurrent 中的一些锁实现。通常锁提供更高的吞吐量和更好的粒度(例如多个并行读取但在任何给定时间只有一次写入)。

您必须考虑的另一件事是所谓的内存屏障。看看这篇有趣的文章http://java.dzone.com/articles/java-memory-model-programer%E2%80%99s

您可以使用 volatile 关键字强制执行发生在语义之前。显式同步(锁或同步代码)也跨越内存屏障并强制在语义之前发生。

最后一条一般建议:您应该不惜一切代价避免共享可变状态。同步是一件令人头疼的事情(性能和维护方面)。错误同步导致的错误非常难以检测。最好针对不变性或孤立的可变性进行设计(例如参与者)。

于 2012-04-17T13:15:11.867 回答
0

答案是它在概述的条件下是线程安全的,因为我只读取处于静态状态的变量并且只更改副本。

于 2012-04-28T21:39:34.833 回答