这是单例设计模式实现之一:饥饿的实现。
我已经了解到这种方式只能创建一个实例并保持线程安全。
很容易理解,只有一个实例,因为实例只在类加载过程中创建。
但是为什么这可以是线程安全的呢?在线文档说它也是因为实例是在加载类时创建的。但我不明白这一点,这个实例如何在多线程情况下保持同步?这对我来说很模糊。有人可以回答这个问题,提前谢谢你。
public class Hunger {
private static Hunger instance = new Hunger();
private Hunger() {}
public static Hunger getInstance() {
return instance; //When multi threads call this, there maybe a problem since only instance is provided.
}
}
答案 0 :(得分:1)
为了确保你安全地初始化你的单例,你可以使用一种特殊的类,称为枚举。例如:
public class GameActivity extends Activity implements SensorEventListener {
//...
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
sensorManager.registerListener((SensorEventListener) this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}
// This is implemented method from SensorEventListener
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// do something
}
// This is implemented method from SensorEventListener
public void onSensorChanged(SensorEvent event) {
// do something
}
}
你会得到这样的输出:
enum Hungry{
INSTANCE;
private static Random rd;
static {
rd = new Random();
System.out.println("Initializing object...");
}
public Integer nextNum() {
return new Random().nextInt(10);
}
}
public class LazyEval {
public static void main(String[] args) throws InterruptedException {
System.out.println("Start...");
Thread.sleep(1000);
System.out.println("First call");
System.out.println(Hungry.INSTANCE.nextNum());
Thread.sleep(1000);
System.out.println("Second Call");
System.out.println(Hungry.INSTANCE.nextNum());
}
}
这是因为,当您第一次访问INSTANCE时,您的JVM将初始化静态块上的所有字段。通过这种方式,您可以存档实时延迟初始化并避免竞争条件。
答案 1 :(得分:0)
Singleton 的线程问题是确保您只初始化一次,并始终向每个提出要求的人提供相同的对象。如果您将初始化推迟到第一个呼叫:
public static Hunger getInstance() {
if (instance == null) {
instance = new Hunger();
}
return instance;
}
你最终可以在if
块中同时使用两个线程,两次调用new
,然后会出现错误。
这是一个如何同步Hunger
对象本身的单独问题;那不是关于 Singleton 模式。
答案 2 :(得分:0)
延迟初始化会导致线程同步问题。 (Lazy init表示在调用createInstance()或getInstance()时创建单例实例)。 但是静态Hunger实例的初始化时间比线程创建时间快。 它不是懒惰的初始化。
但它不是完全同步。 因为它只在创建实例时可用。 也许在线文档说这只是在创建singlton实例时可用。 因此,在放置任何公共资源成员时必须使用线程锁定对象。