2014-04-15 131 views
5
MyObject myObj ... 

public void updateObj(){ 
    MyObject newObj = getNewMyObject(); 
    myObj = newObj; 
} 

public int getSomething(){ 
    //O(n^2) operation performed in getSomething method 
    int something = myObj.getSomething(); 
    return something; 
} 

假设主线程定期调用updateObj()和子线程很频繁地调用getSomething()方法。我需要锁吗?

我需要一个锁(或声明为synchronized方法)之前myObj = newObj;int something = myObj.getSomething();

有人认为我不需要这里的锁,因为在Java中,赋值操作(例如myObj = newObj;)是原子。但我没有得到的是myObj.getSomething();这不是一个原子操作,但它的O(n^2),所以我认为仍然需要一个锁定。它是否正确?

在此先感谢。

+0

'将方法声明为synchronized'将不起作用。由于你没有改变myObj,'getSomething'可以使用旧版本还是新版本,如果是,那么非同步应该可以。 –

+6

如果可以使用'myObj'的旧值,则不需要锁定。但是你更新了它是有原因的,不是吗? – cHao

+0

我同意@cHao。但是,如果您可以概述getSomething()的相关行,那么我们可以给出明确的答案。 – RRM

回答

0

是的,你需要在这里锁定。因为我可以看到两种不同的功能是由不同的线程调用的,并且您在getSomething()方法中使用myObj。 现在假设你的子线程正在执行getSomething()并且同时你的主线程有变化myObj那么你的程序将成为竞态条件的受害者,并且你可能得不到所需的输出。 但它取决于您编写的整体程序。希望这有助于

+0

子线程将在* myObj中新运行'doSomething',或者旧的时间 - 它完成一个。无论从哪一个开始,它都会完成,而后者不一定是世界末日。 :)这完全取决于为什么'myObj'已经改变。 (不是我的downvote,顺便说一句。) – cHao

+0

@cHao但是新旧程序中使用和传递的一些业务逻辑是否会影响程序流?让我纠正,如果错误 –

+0

@SanjayRajjadi这将如何导致竞争状态? –

0
  • updateObj()需要被同步,使得共享可变myObj写入原子。

    • MyObjects.getSomething()如果使用共享可变值,则需要使用同步方法。
+1

参考读取和写入在Java中已经是原子性的。如果这是唯一的问题,你不需要做任何额外的事情来获得原子性。什么不是原子是读/修改/写......这似乎不是这里的情况。 – cHao

3

您需要声明myObject的波动,否则getSomething()方法可能不会看到更新的对象。除此之外,我在上面的代码中看不到任何同步问题

2

是的,您必须正确同步对共享变量的访问。根据Java Memory Model,在所有可能的执行过程中,您的代码不保证读取和写入之间的关系为happens-before

正确的同步并不总是意味着使用锁;在你的情况下,声明myObj为volatile可以完成这项工作(假设你在构建之后不会改变它)。

1

对引用变量的写入实际上是原子的。

但是,如果没有其他线程不能保证看到的myObj更新值发挥到了极致,他们只能看到它的初始值(null,如果你没有在分配给它的锁(或其他某种同步)构造函数)。

你会捉襟见肘,因为它表现出的正是这种极端的行为这样的方式来编写程序,但没有同步,你一定会得到不一致的结果,当一个线程调用updateObj,比一些其他线程调用getSomething和使用过时的myObj实例。

确保getSomething使用最新的myObj的最简单方法是声明myObjvolatile

+0

问题可能比过时的值更糟。读者线程可能会在myObj中看到部分数据,就好像它是部分构建的一样。 –