我在我的一个应用程序中编写了类似的代码,但我不确定它是否是线程安全的。
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和平滑运动,我不希望该线程一直等待同步锁定。因此,除非确实有必要,否则我希望避免使用同步。那么这里真的有必要吗?或者还有其他更好的方法可以解决这个问题吗?
顺便说一句,线程是否收到对象的旧副本并不重要。
答案 0 :(得分:5)
至于当前版本的状态,它肯定是不是线程安全的,因为myObject
的并发访问将建立数据竞争。
您没有指定此项,但如果MyObject
不是线程安全的,那么无论您对所显示的代码执行什么操作,您的程序都不会是线程安全的。
线程是否收到对象的旧副本无关紧要。
Java内存模型允许比通过数据竞争访问的对象更糟糕的事情:
为了获得最佳FPS和平滑运动,我不希望该线程一直等待同步锁定。
您是否花了很多精力来衡量线程等待锁定的时间?我的猜测:你没有,因为时间太短,无法察觉。
但是,你的情况甚至没有调用锁:只需使你的实例变量volatile
足以保证线程之间安全共享对象。
答案 1 :(得分:4)
不,它不是线程安全的 - 这可能发生:
myObject
时可能看不到getObject
的最新版本(显然可以使用)myObject
getObject
所做的任何更新
MyObject
的更新引用,该引用处于不一致状态(例如,部分构造)解决这些问题的最简单方法是标记myObject
volatile。
答案 2 :(得分:2)
你实际上有很多并发症:
myObject需要易变。 (否则其他线程可能永远不会看到变化)。
在访问MyClass之前,myObject的初始值将完全构造,因此在这种情况下是安全的,但是通常需要注意组合对象的构造和多线程。
答案 3 :(得分:0)
是的,只要您将myObject
标记为volatile
,在上述条件下它就是线程安全的。您始终会从MyObject
获得正确的getObject()
个实例。
答案 4 :(得分:0)
您应该创建共享变量volatile
,让线程知道其他线程/进程/ etc可能会更改其值。
除此之外,代码中没有并发问题。
创建MyObject
实例时创建MyClass
实例的第二行完全没问题。在完全构造MyObject
的实例之前,没有人可以访问共享变量(除非你从构造函数中泄漏共享变量)。
setObject
方法也很好 - 它只是将一个对象分配给共享变量myObject
。由于作业是原子的,因此无需担心。