2014-10-06 127 views
1

我无法在任何地方找到这个特定场景。同步访问非易失性字段线程安全吗?

如果我从两个线程同时呼叫init(),其中一个呼叫是否保证看到time不再为空? time是否也需要volatile

它是否像join()这是一个同步点?

private Long time; 

synchronized void init() { 
    if (time != null) { 
     throw new IllegalStateException("Already initialised."); 
    } 

    this.time = System.currentTimeMillis(); 
} 
+0

我认为如果变量是非易失性的,那么在多个处理单元上可能会出现缓存问题。 – 2014-10-06 05:35:16

+2

如果这不是线程安全的,'synchronized'将完全无用。 – Mat 2014-10-06 05:36:40

+0

*同步*关键字隐式暗示a *发生在*关系之前。所以,是的,它是线程安全的。 – TheLostMind 2014-10-06 05:37:31

回答

3

当一个线程进入该​​方法,它获取一个implicit锁在例如,它执行到实例的state的变化是将其他线程可见,等待进入同步方法。

当一个同步方法退出时,它自动地建立一个 之前发生的关系具有用于相同对象的 同步方法的任何后续调用。 这保证对所有线程都可见对象状态的更改 。

文档中的最后一行提到它很清楚。这个国家是volatile还是non-volatile并不重要。

+0

如果不是“同步”方法,而是将语句包装在“synchronized(lockObject)”块中?现在我正在改变锁对象以外的其他对象的状态。 – Monstieur 2014-10-06 05:48:06

+0

是的,在这种情况下,它不能得到保证。然后你可以使用volatile关键字。 – BatScream 2014-10-06 05:50:39

+4

您正在从其上下文中提取报价。拥有一个同步块不会保证所有**线程都可以看到这些更改,只有这些线程*随后使用一个同步块获取同一监视器。该引用仅在您从http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html取消引用的页面上的示例类“SynchronizedCounter”的上下文中有效(不是您需要引用从哪里引用) – 2014-10-06 05:55:13

0

更简单的解决方案是使用静态类初始化程序。

class TimeHolder { 
     public static final long time = System.currentTimeMillis(); 
} 

假定您是初次使用该类时还是创建对象时启动。

+0

这只是一个例子。我需要线程安全的东西。 – Monstieur 2014-10-06 06:23:44

+0

问题越真实,答案越贴切。 – 2014-10-06 06:37:09