单例模式
单例模式分为懒汉式和饿汉式
目的:只创建一个对象实例
需要将构造器私有化,防止通过new的方式创建对象实例
懒汉式:
延迟加载 --> 需要用到的时候,先去判断该对象实例是否为null,如果为null才会重新创建
缓存思想 --> 不为null则直接使用已缓存的对象实例
线程不安全
1 public class Singleton { 2 private static Singleton singleton; 3 4 private Singleton() {} 5 6 public static Singleton getInstance(){ 7 if(singleton == null){ 8 singleton = new Singleton(); 9 } 10 return singleton; 11 } 12 }
当该对象实例不一定用到时,可以使用懒汉模式(延迟加载)
懒汉式(线程安全,synchronized):
1 public class Singleton { 2 3 private static Singleton instance; 4 5 private Singleton (){} 6 7 public static synchronized Singleton getInstance() { 8 if (instance == null) { 9 instance = new Singleton(); 10 } 11 return instance; 12 } 13 }
效率低(不管对象实例是否为null,都会上锁)
懒汉式(线程安全,双重检查加锁):
1 public class Singleton { 2 3 private volatile static Singleton singleton; 4 5 private Singleton (){} 6 7 public static Singleton getSingleton() { 8 if (singleton == null) { 9 synchronized (Singleton.class) { 10 if (singleton == null) { 11 singleton = new Singleton(); 12 } 13 } 14 } 15 return singleton; 16 } 17 }
volatile:可见性,其它线程可见,直接读取主内存中的数据,使其线程获取的总是最后修改后的值
先检查对象实例是否为null,不为null就直接返回,为null才进入同步锁;
此时再次检查实例对象是否为null,为null才创建。
饿汉式:
线程安全
空间换时间
1 public class Singleton { 2 private static Singleton instance = new Singleton(); 3 4 private Singleton (){} 5 6 public static Singleton getInstance() { 7 return instance; 8 } 9 }
当对象实例一定会用到时,可以使用饿汉模式(类加载时就创建对象实例)
静态内部类实现单例:
线程安全
延迟加载
1 public class Singleton { 2 3 private static class SingletonHolder { 4 private static Singleton INSTANCE = new Singleton(); 5 } 6 7 private Singleton (){} 8 9 public static final Singleton getInstance() { 10 return SingletonHolder.INSTANCE; 11 } 12 }
枚举实现单例:
线程安全
1 enum SingleEnum{ 2 //枚举元素 SINGLE_ENUM 默认就是该对象一个实例 3 SINGLE_ENUM; 4 }
利用枚举和map集合实现只创建 两个 对象实例
1 public class SingleNumControl { 2 private int num = 0; 3 private Map<Integer,SingleNumControl> map = new HashMap<>(); 4 5 private SingleNumControl() {} 6 7 public SingleNumControl getInstance(){ 8 SingleNumControl single = map.get(num); 9 if(single == null){ 10 single = new SingleNumControl(); 11 map.put(num,single); 12 } 13 num++; 14 if(num >= 2){ 15 num = 0; 16 } 17 return single; 18 } 19 20 public static void main(String[] args) { 21 SingleNumControl singleNumControl = new SingleNumControl(); 22 for (int i = 0; i < 8; i++) { 23 System.out.println(singleNumControl.getInstance()); 24 } 25 } 26 27 }