2011-03-23 37 views
1

Memory Consistancy Property起,我们知道: “将对象放入任何并发集合之前的一个线程中的操作发生 - 在从该集合中访问或从中删除该元素之后的操作另一个线程“。java.util.concurrent中的内存一致性

这是否意味着:如果我创建一个对象,并把它变成的ConcurrentLinkedQueue在一个线程,另一个线程会看到对象的所有属性没有物体上的其他同步?

例如:

public class Complex{ 

    int index; 

    String name; 

    public Complex(int index, String name){ 

    this.index = index; 

    this.name = name; 

    } 

    public String getName(){ 

    return name; 

    } 

    public int getIndex(){ 

    return index; 

    } 

} 

public class SharedQueue{ 

    public static ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); 

} 

在一个线程:

...........

Complex complex = new Complex(12, "Sam"); 

SharedQueue.queue.add(complex); 

...... .....

在另一个线程

...... 

Complex complex = SharedQueue.queue.poll(); 

System.out.printly(complex.getIndex() + ";" + complex.getName()); 

.............

是否第二个线程一定会看到complex对象的属性?如果第二个线程恰好获取对象并在第一个线程将该对象放入队列后将其打印出来。

我们知道,在正常情况下,我们应该在多线程环境中,如果它是同步共享对象。

public class Complex{ 

    int index; 

    String name; 

    public Complex(int index, String name){ 

    this.index = index; 

    this.name = name; 

    } 

    public synchronized String getName(){ 

    return name; 

    } 

    public synchronized int getIndex(){ 

    return index; 

    } 

} 

回答

0

JSR 133还规定,对象的最终领域是完整的,可见的构造完成时所有线程。这种支持是在Java 5.0(2004年)中添加的。您的对象在所有线程中都不可见并且正确无需其他操作。

使用不可变对象上同步不能达到在这种情况下任何东西。

有大量的文件另有哪个状态和这些通常早2004)

+0

JLS在哪里指定了这个?众所周知的双重检查单例示例表明,如果没有适当的同步,其他线程可以观察到部分构建的对象。 – axtavt 2011-03-23 15:41:48

+0

@axtavt,对不起,没有在JLS中,它在JSR 133中。 – 2011-03-23 15:52:57

+0

JSR 133是JLS 3的内存模型,但它没有提供关于构造函数的任何保证(除'final'字段外)。 – axtavt 2011-03-23 15:57:17

0

完全正确。在这种情况下,ConcurrentLinkedQueue可用作同步器。

0

这意味着如果线程A将一个对象放入集合中,并且线程B从那里获取它,则线程B可以在将对象放入集合之前查看由线程A完成的任何动作的结果(以及动作发生在之前他们在其他线程等)。这些行动包括对象的初始化(如果它是由线程A完成),让线程B可以看到一致的状态的对象。

注意,它不提供有关发生在线程A放置对象进入收集或约其他线程的操作(除了用传递连接动作之前发生顺序,如上所述)之后的动作的任何保证,因此,如果要在将对象放入集合后进行修改,则仍然需要同步。

顺便说一下,你的“正常情况下”样本已损坏,因为构造函数中的动作不同步。

1
  1. 所有线程都看到它们可以引用的所有对象,所以是的,这也适用于集合。并发集合正在使用同步不会因为两个或更多个线程同时访问它们而中断(例如,for-loop可能会中断),因此您可以使用它们在线程之间共享对象。

  2. 如果你的对象是不可改变的,即只读的,就像你上面的Complex类(添加最终修饰符)一样,那么你不需要同步对它的访问,因为它是线程安全的。

同步的关键是确保您的变量在n个操作中保持一致。例如:

如果要计算

i = i + 2; 

那么这个由我的第一个读数值,加2,然后在我设定值回。

现在,如果有其他线程在我添加2后才更新,那么您实际上会覆盖此更新,因为您仍然保留基于前一个值+ 2的总和,并将其设置回i。

+0

'Complex'不是不可变的,因为它的字段不是'final'。没有适当的同步,其他线程可以在部分构建的状态下观察它。 – axtavt 2011-03-23 15:43:32

+0

相应地更新了答案,希望他们有一天能够杀死那部分建设状态。 – ThomasRS 2011-03-23 15:55:55