一、单例模式
单例模式(Singleton Pattern) 是一个比较简单的模式,其定义如下:
Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例)
单例模式通过定义一个私有访问权限的构造函数来避免被其他类new出来一个对象,然后该类自己创建一个实例,通过一个静态方法对外提供这个实例对象。
单例模式的通用代码如下:
代码清单1
public class Singleton { private static final Singleton singleton = new Singleton(); private Singleton(){} public static Singleton getSingleton(){ return singleton; } }
单例模式的注意事项
首先,在高并发情况下,请注意单例模式的线程同步问题。单例模式有几种不同的实现方法,上面的例子不会出现产生多个实例的情况,但是下面的代码就有可能出现多个实例。
代码清单2:
public class Singleton { private static final Singleton singleton = null; private Singleton(){} public static Singleton getSingleton(){ if(singleton == null){ singleton = new Singleton(); } return singleton; } }
如果一个线程A执行到singleton = new Singleton(),但是还没有获得对象(对象初始化是需要时间的),第二个线程B也在执行,执行到if(singleton == null),那么线程B获得判断条件也是为真,于是继续执行下去,线程A获取了一个对象,线程B也获得了一个对象,在内存中就会出现两个对象。
解决线程不安全的方法很多,可以在getSingleton方发前加synchronized关键字,也可以在getSingleton方法内加synchronized来实现,但都不是优秀的单例模式,建议读者使用如代码清单1的方式来实现单例模式。
代码清单1的单例称为饿汉式单例。
增加了synchronized关键字的代码清单2单例称为懒汉式单例。
二、单例模式的扩展
如果一个类要求可以产生多个对象,直接new就可以了。如果一个类要求只能有一个对象,那么就使用单例模式。
但是如果要求一个类只能产生两三个对象呢?该怎么实现?
//皇帝类 import java.util.ArrayList; import java.util.Random; public class Emperor { private static int maxNumOfEmperor = 2; private static ArrayList<String> nameList = new ArrayList<>(); private static ArrayList<Emperor> emperorList = new ArrayList<>(); private static int countNumOfEmperor = 0; static { for(int i = 0; i < maxNumOfEmperor; i++){ emperorList.add(new Emperor("皇帝"+i)); } } private Emperor(){} private Emperor(String name){ nameList.add(name); } public static Emperor getInstance(){ Random random = new Random(); countNumOfEmperor = random.nextInt(maxNumOfEmperor); return emperorList.get(countNumOfEmperor); } } //大臣类 public class Minister { public static void main(String[] args) { for(int day = 0; day < 10; day++){ Emperor emperor = Emperor.getInstance(); System.out.println(emperor); } } } 打印结果: [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
从对象地址可以看到只产生了两个对象
这种需要产生固定数量对象的模式叫做有上限的多例模式,它是单例模式的一种扩展。