我正在阅读“实践中的Java并发”。我们有一个函数如下:
public class LazyInitRace {
private ExpensiveObject instance = null;
public ExpensiveObject getInstance() {
if (instance == null)
instance = new ExpensiveObject();
return instance;
}
}
作者说,这不是线程安全的。我认为,“实例”变量不是静态变量,因此线程安全。 我认为只有当两个线程访问同一个类实例时,它才会变得不安全。我需要知道我的想法是否正确?
答案 0 :(得分:8)
变量是非static
还是static
并不重要。目的是为每个实例创建一个并仅创建一次。
这里没有填充 - 当两个并行线程进入此方法时,变量可能对它们两者显示为null
,并且两者都将创建新实例。您需要使用synchronized
包装代码或方法。
答案 1 :(得分:2)
线程安全是一种适用于多线程程序环境的计算机编程概念。如果一段代码仅以保证多个线程同时安全执行的方式操作共享数据结构,则它是线程安全的。
class Singleton {
private volatile static Singleton _instance;
private Singleton() {
// preventing Singleton object instantiation from outside
}
/*
* 1st version: creates multiple instance if two thread access
* this method simultaneously
*/
public static Singleton getInstance() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}
/*
* 2nd version : this definitely thread-safe and only
*creates one instance of Singleton on concurrent environment
* but unnecessarily expensive due to cost of synchronization
* at every call.
*/
public static synchronized Singleton getInstanceTS() {
if (_instance == null) {
_instance = new Singleton();
}
return _instance;
}
/*
* 3rd version : An implementation of double checked locking of Singleton.
* Intention is to minimize cost of synchronization and improve performance,
* by only locking critical section of code, the code which creates instance of Singleton class.
* By the way this is still broken, if we don't make _instance volatile, as another thread can
* see a half initialized instance of Singleton.
*/
public static Singleton getInstanceDC() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null) {
_instance = new Singleton();
}
}
}
return _instance;
}
}
答案 2 :(得分:0)
当我们说一个程序是线程安全的时,它意味着该程序的所有线程都有一个 CONSISTENT 视图来查看程序中数据的值。这是一个简单的例子。假设something
是ExpensiveObject
,它已由getInstance
方法初始化,并且对程序的所有线程都可见。此外,classObject
是Class<ExpensiveObject>
类型的对象。现在考虑以下代码片段由某个线程运行:
if(something != null)
classObject = something.getClass();
看起来NullPointerException
是不可能的吗?不是。在if(something != null)
和classObject = something.getClass();
之间,另一个帖子可以将something
的值更改为null
。这个程序不是线程安全的,因为对something
的读取和写入不是同步,这可以确保所有线程都具有something
值的一致视图。