单例模式(Singleton Pattern)
定义:确保某个类只有一个实例,并且自行实例化并向整个体系提供这个实例
需求:保证对象只创建一次
场景:线程池、缓存、日志对象、对话框等常被设计为单例。
Singleton 通过构造方法限定 private 避免类在外部被实例化,在同一个虚拟机范围内,Singleton 的实例只能通过 getInstance 访问。
事实上,通过 Java 的反射机制能够实例化构造函数为 private 的类,基本是上所有的单例都失效。
优点:减少了内存的消耗,重用。
单例通用代码01:(饿汉式)
public class Singleton { private static final Singleton singleton = new Singleton(); private Singleton(){ } public static Singleton getInstance(){ return singleton; }
public void say(){} }
可能产生多个实例02:(懒汉式)
public class Singleton{ private static Singleton instance = null;
private Singleton(){ } public static Singleton getInstance(){ if(instance == null){if(instance == null){ instance = new Singleton(); } } return instance; } }
在高并发的情况下,可能在 instance ==null 与 new Singleton 之间产生多例。
解决多例的问题:03(懒汉式)方法上加锁
public class Singleton { private static Singleton instance = null; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance==null){ instance = new Singleton(); } return instance; } public void say(){ //todo something } }
使用双检查锁:04(懒汉式)双检查,方法内加锁
public class Singleton { private static Singleton instance = null; private Singleton(){} public static Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class) { if(instance==null) { instance = new Singleton(); } } } return instance; } public void say(){ //todo something } }
饿汉式的单例模式,不会出现线程安全的问题。
懒汉式本身是非线程安全的。
方法上加锁与方法内双检查加锁:方法上加锁,虽然线程安全,但是每次都要同步,会影响性能 99% 的情况下是不需要同步的。
方法内检查2次加锁,确保第一次调用的时候加锁,这样是线程安全的,避免了性能的损耗。
扩展:固定数量的单例
public class ExtSingleton { //最大单例个数 private static int maxNumOfSingleton = 2; //单例名称 private static ArrayList<String> nameList = new ArrayList<>(); //单例集合 private static ArrayList<ExtSingleton> singletons = new ArrayList<>(); private ExtSingleton(){} private ExtSingleton(String name){ nameList.add(name); } static { for(int i=0;i<maxNumOfSingleton;i++){ singletons.add(new ExtSingleton("singleton:"+i)); } } public static ExtSingleton getInstance(){ //todo 获取单例某个对象 return singletons.get(0); } }