单利模式即在整个系统运行过程中类只有一个实例存在。
例如读取系统配置文件,重复加载浪费资源,但是又经常用到的对象。
1 package com.hbcfc.lp; 2 /** 3 * @author silence 4 * @date 2021/5/5 18:12 5 */ 6 public class Singleton { 7 private int a=0; 8 private static Singleton singleton = new Singleton(); 9 10 private Singleton(){ 11 12 } 13 private int next(){ 14 return ++a; 15 } 16 private static Singleton getInstance(){ 17 18 return singleton;//静态方法属于类,里面不可用this关键字,伪变量this表示这个实例 19 } 20 21 public static void main(String[] args) { 22 System.out.println(Singleton.getInstance().next());//生成唯一序列号应用 23 System.out.println(Singleton.getInstance().next()); 24 System.out.println(Singleton.getInstance().next()); 25 } 26 }
1 package com.hbcfc.lp; 2 /** 3 * @author silence 4 * @date 2021/5/5 18:12 5 */ 6 public class Singleton { 7 private static Singleton singleton; 8 9 private Singleton(){ 10 11 } 12 private static Singleton getInstance(){ 13 if(singleton==null){ 14 return singleton= new Singleton(); 15 } 16 else{ 17 return singleton;//静态方法属于类,里面不可用this关键字,伪变量this表示这个实例 18 } 19 20 } 21 22 }
懒汉式在饿汉式的基础上做了改进实现了lazy Loading,但是线程是不安全的。
1 package com.hbcfc.lp; 2 /** 3 * @author silence 4 * @date 2021/5/5 18:12 5 */ 6 public class Singleton { 7 private static Singleton singleton; 8 9 private Singleton(){ 10 11 } 12 private static Singleton getInstance(){ 13 synchronized (Singleton.class){//为了解决线程安全问题第一反应枷锁 14 if(singleton==null){ 15 return singleton= new Singleton(); 16 } 17 return singleton;//静态方法属于类,里面不可用this关键字,伪变量this表示这个实例 18 } 19 } 20 21 }
上述加锁解决了线程安全问题但是带来性能开销问题,如果说实例不为空的情况下是不需要进入到锁的。这里可以再加一层检查。
1 package com.hbcfc.lp; 2 /** 3 * @author silence 4 * @date 2021/5/5 18:12 5 */ 6 public class Singleton { 7 private static Singleton singleton; 8 9 private Singleton(){ 10 11 } 12 private static Singleton getInstance() { 13 if (singleton == null) {//减少性能开销为空才进入锁 14 synchronized (Singleton.class) { 15 if (singleton == null) { 16 return singleton = new Singleton(); 17 } 18 } 19 } 20 return singleton;//静态方法属于类,里面不可用this关键字,伪变量this表示这个实例 21 } 22 }
还有个隐藏的问题:指令重排序,对象创建的过程
1.分配内存空间
2.对象初始化
3.初始化的对象指向分配的内存空间
有些编译器为了性能原因,可能将第二和第三步进行了指令重排序颠倒了顺序,先指向分分配的内存空间然后再去初始化。这样多线程情况下会出现下面问题,线程A还没来得及初始化对象,线程B通过了检查返回了实力进行调用。这个时候就需要禁止指令重排序。使用volatile关键字。
1 package com.hbcfc.lp; 2 /** 3 * @author silence 4 * @date 2021/5/5 18:12 5 */ 6 public class Singleton { 7 private static volatile Singleton singleton;//保证原子性读永远发生在写之后 8 9 private Singleton(){ 10 11 } 12 private static Singleton getInstance() { 13 if (singleton == null) { 14 synchronized (Singleton.class) { 15 if (singleton == null) { 16 return singleton = new Singleton(); 17 } 18 } 19 } 20 return singleton;//静态方法属于类,里面不可用this关键字,伪变量this表示这个实例 21 } 22 }
未完待续.
原文:https://www.cnblogs.com/silencelp/p/14732424.html