在Java中初始化对象Thread Safe

时间:2014-02-14 11:15:41

标签: java multithreading object initialization

我在我的一个应用程序中编写了类似的代码,但我不确定它是否是线程安全的。

public class MyClass {
    private MyObject myObject = new MyObject();

    public void setObject(MyObject o) {
        myObject = o;
    }

    public MyObject getObject() {
        return myObject;
    }
}

setObject()getObject()方法将由不同的线程调用。 getObject()方法将由一个继续在Canvas上绘图的线程调用。为了获得最佳FPS和平滑运动,我不希望该线程一直等待同步锁定。因此,除非确实有必要,否则我希望避免使用同步。那么这里真的有必要吗?或者还有其他更好的方法可以解决这个问题吗?

顺便说一句,线程是否收到对象的旧副本并不重要。

5 个答案:

答案 0 :(得分:5)

至于当前版本的状态,它肯定是不是线程安全的,因为myObject的并发访问将建立数据竞争。

您没有指定此项,但如果MyObject不是线程安全的,那么无论您对所显示的代码执行什么操作,您的程序都不会是线程安全的。

  

线程是否收到对象的旧副本无关紧要。

Java内存模型允许比通过数据竞争访问的对象更糟糕的事情:

  • 一个线程可能总是收到同一个对象(它碰巧读的第一个);
  • 线程可能会观察到对象只有一些可达到的值被初始化(撕裂的对象)。
  

为了获得最佳FPS和平滑运动,我不希望该线程一直等待同步锁定。

您是否花了很多精力来衡量线程等待锁定的时间?我的猜测:你没有,因为时间太短,无法察觉。

但是,你的情况甚至没有调用锁:只需使你的实例变量volatile足以保证线程之间安全共享对象。

答案 1 :(得分:4)

不,它不是线程安全的 - 这可能发生:

  • 线程在调用myObject时可能看不到getObject的最新版本(显然可以使用)
  • 线程可能从不在调用myObject
  • 时看到其他线程对getObject所做的任何更新
  • 线程可能会看到对MyObject的更新引用,该引用处于不一致状态(例如,部分构造)

解决这些问题的最简单方法是标记myObject volatile。

答案 2 :(得分:2)

你实际上有很多并发症:

  1. myObject需要易变。 (否则其他线程可能永远不会看到变化)。

  2. 在访问MyClass之前,myObject的初始值将完全构造,因此在这种情况下是安全的,但是通常需要注意组合对象的构造和多线程。

答案 3 :(得分:0)

是的,只要您将myObject标记为volatile,在上述条件下它就是线程安全的。您始终会从MyObject获得正确的getObject()个实例。

答案 4 :(得分:0)

您应该创建共享变量volatile,让线程知道其他线程/进程/ etc可能会更改其值。

除此之外,代码中没有并发问题。

创建MyObject实例时创建MyClass实例的第二行完全没问题。在完全构造MyObject的实例之前,没有人可以访问共享变量(除非你从构造函数中泄漏共享变量)。

setObject方法也很好 - 它只是将一个对象分配给共享变量myObject。由于作业是原子的,因此无需担心。