文章来源:https://blog.csdn.net/a2572371/article/details/78150243
本次直接应用经典案列
单例模式:饿汉模式以及懒模式 饿汉模式:线程安全,不会产生多个实例。但如果加载耗时,增加项目初始化时间,如果在运行过程中,没有用到,可能增加空间的浪费 懒汉模式:充分利用资源,实现懒加载策略。(可能线程不安全,需要用户自己优化)
例子 饿汉模式
/** * Description:饿汉模式 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:52 */public class HungrySingleton { /** * 利用classLoader加载 */private static final HungrySingleton hungrySingleton = new HungrySingleton(); /** * 私有的构造函数:不让外界创建 */private HungrySingleton() { } //提供唯一对外,反射除外public static HungrySingleton getInstance() { return hungrySingleton; }}
懒汉模式:几种变形
1.不加任何修饰(不安全)
/** * Description:懒汉模式 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton { /** * 未初始化 */private static LazySingleton instance; private LazySingleton() { } public static LazySingleton getInstance() { //第一次调用会初始化.不过多线程情况下,会重复初始化(线程安全问题)if (instance == null) instance = new LazySingleton(); return instance; }}
2.加synchronized(不安全)
/** * Description:懒汉模式 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton1 { /** * 未初始化 */private static LazySingleton1 instance; private LazySingleton1() { } public static LazySingleton1 getInstance() { if (instance == null) { //但是如果线程A和B同时执行到了Synchronized(singleton.class), // 虽然也是只有一个线程能够执行,假如线程B先执行,线程B获得锁,线程B执行完之后,线程A获得锁, // 但是此时没有检查singleton是否为空就直接执行了,所以还会出现两个singleton实例的情况synchronized(LazySingleton1.class) { instance = new LazySingleton1(); } } return instance; }}
2.加synchronized以及判断是否NULL(不安全)
[java] view plain copy
- <code class="language-java">/**
- * Description:懒汉模式:双重检查
- * User: lc
- * Date: 2017/9/30 0030
- * Time: 下午 3:58
- */
- public class LazySingleton2 {
- /**
- * 要volatile修饰
- * 理由:比如2个线程A/B线程。
- */
- private static LazySingleton2 instance;
-
- private LazySingleton2() {
-
- }
-
- public static LazySingleton2 getInstance() {
-
- if (instance == null) {
- synchronized (LazySingleton2.class) {
-
- if(instance == null)
- //此处还是有问题:虽然做了双重判断。 因为 newLazySingleTon1()是非原子操作
- // A a=new A()
- // 进行了三步操作:1.申请空间2.将引用指向该空间地址3.初始化构造
- //在理想情况下,按照1->3->2的步骤执行时,双检锁形式可以正常工作,但是由于Java内存模型,允许重排序,所以
- //完全可能按照1->2->3的顺序执行,则导致双检锁形式出现问题。即线程1在执行single=new Singleton()语句时,刚好按照1->2->3的顺序 //执行到step2处,此时,instance指向mem内存区域,而该内存区域未被初始化;同时,线程2在第一个if(instance==null)地方发现instan // ce不为null了,于是得到这<span style="font-family:Arial, Helvetica, sans-serif;">个为被初始化的实例instance进行使用,导致错误。</span></code>
//synchronized:允许修饰的对象,可见性,但是可以允许jvm的进行重排序
instance = new LazySingleton2();
return instance;
}
}
return instance;
}
}
3.加synchronized以及volatile(安全)
/** * Description:懒汉模式:双重检查 * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class LazySingleton2 { /** * 要volatile修饰 * 理由:比如2个线程A/B线程。 */private volatile static LazySingleton2 instance; private LazySingleton2() { } public static LazySingleton2 getInstance() { if (instance == null) { synchronized (LazySingleton2.class) { if (instance == null) instance = new LazySingleton2(); } } return instance; }}
4.静态内部类(安全)
/** * Description:懒汉模式: * User: lc * Date: 2017/9/30 0030 * Time: 下午 3:58 */public class StaticLazySingleton { /** * 1.私有内部类,外部不知道该类的存在 * 2.外部类初始化的时候,该内部类还没加载,只有通过第一次调用才(比如这个例子:触发getInstance())加载,加载是利用jvm加载,而jvm加载某个类,只能加载一次,所以是只能有一个class类。故线程安全 * 3.对外提供唯一的出口 */private StaticLazySingleton() { } // 静态内部类private static class StaticLazySingletonInstance { private static final StaticLazySingleton staticLazySingleton = new StaticLazySingleton(); } public static StaticLazySingleton getInstance() { return StaticLazySingletonInstance.staticLazySingleton; }}
|
|