这个比较短,我就贴下代码,这都是个人,从网上搜搜,思考,总结的,
需要有一点基础的,想全面点了解的可以看看。
希望能对大家有帮助。
/*
* 懒汉式单例
* 类进内存对象还没有存在,只有调用方法时才建立对象
*对象是方法被调用时才初始化,也叫做对象的延时加载
*它是线程不安全的,并发环境下很可能出现多个Singleton实例
*
*/
public class Singleton1 {
/* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private static Singleton1 instance = null;
/* 私有构造方法,防止被实例化 */
private Singleton1() {
}
/* 静态工程方法,创建实例 */
// 多线程不安全
/*
* public static Singleton1 getInstance(){ if (instance == null){ instance =
* new Singleton1(); } return instance; }
*/
// 解决方案一:
/*
* 但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降, 因为每次调用getInstance(),都要对对象上锁,
* 事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了
*/
/*
* public static synchronized Singleton1 getInstance(){ if (instance ==
* null){ instance = new Singleton1(); } return instance; }
*/
// 解决方案二:
/*
* 将synchronized关键字加在了内部,也就是说当调用的时候是不需要加锁的,
* 只有在instance为null,并创建对象的时候才需要加锁,性能有一定的提升
*
* 但是,这样的情况,还是有可能有问题的,看下面的情况:
* 在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();
* 语句是分两步执行的。但是JVM并不保证这两个操作的先后顺序,
* 也就是说有可能JVM会为新的Singleton实例分配空间,
* 然后直接赋值给instance成员,然后再去初始化这个Singleton实例。这样就可能出错了,
* 我们以A、B两个线程为例:
* a>A、B线程同时进入了第一个if判断
* b>A首先进入synchronized块,由于instance为null,所以它执行instance = new Singleton();
* c>由于JVM内部的优化机制,JVM先画出了一些分配给Singleton实例的空白内存,
* 并赋值给instance成员(注意此时JVM没有开始初始化这个实例),然后A离开了synchronized块。
* d>B进入synchronized块,由于instance此时不是null
* 因此它马上离开了synchronized块并将结果返回给调用该方法的程序。
* e>此时B线程打算使用Singleton实例,却发现它没有被初始化,于是错误发生了。
* 最終解決方法參見 饿汉单例 模式 Singleton2.java
*/
public static Singleton1 getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton1();
}
}
}
return instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve() {
return instance;
}
}
|
|