单例模式定义
确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个模型
优点:
- 减少内存开支
- 减少系统的性能开销
- 避免对资源的多重占用
- 可以在系统中设置全局的访问点
缺点:
- 单例模式一般没有接口,扩展困难,除了修改代码没有选择 因为单例模式要求“自行实例化”,所以接口对于单例来说没有意义,
- 对测试不利,在并发编程中单例模式没有开发完成,是不能进行测试的。没有接口也不能使用mock的方式拟造一个对象
- 与单一职责有冲突,一个类应该只实现一个逻辑,而不关心是否是单例。
实现:
1.饿汉式
public class Emperor {
private final static Emperor emperor = new Emperor();
private Emperor(){
//构造函数私有化 避免被其他类new出来一个对象 只有自己可以new一个对象出来
}
public static Emperor getInstance(){
return emperor;
}
public static void say(){
System.out.println("我是皇帝……");
}
}
2.懒汉式
public class Emperor1 {
private static Emperor1 emperor = null;
private Emperor1(){
//构造函数私有化 避免被其他类new出来一个对象 只有自己可以new一个对象出来
}
public static Emperor1 getInstance(){
if (emperor==null){
Emperor1 emperor1= new Emperor1();
}
return emperor;
}
public static void say(){
System.out.println("我是皇帝……");
}
}
3.线程安全的饿汉
添加关键字synchronized
private static Emperor1 emperor = null;
private Emperor1(){
//构造函数私有化 避免被其他类new出来一个对象 只有自己可以new一个对象出来
}
public static synchronized Emperor1 getInstance(){
if (emperor==null){
Emperor1 emperor1= new Emperor1();
}
return emperor;
}
public static void say(){
System.out.println("我是皇帝……");
}
4.双重校验锁
public class Emperor2 {
private static volatile Emperor2 emperor ;
private Emperor2(){ }
public static Emperor2 getInstance(){
if (emperor==null){
synchronized (Emperor2.class){
if (emperor == null){
Emperor2 emperor2= new Emperor2();
}
}
}
return emperor;
}
public static void say(){
System.out.println("我是皇帝……");
}
}
5.静态内部类
无锁化编程 线程安全 执行效率高
private static class EmperorInstance{
private static final Emperor3 emperor = new Emperor3();
}
private Emperor3() {
}
public static Emperor3 getInstance(){
return EmperorInstance.emperor;
}
6.枚举
线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用
public enum Emperor66 {
INSTANCE; //枚举元素本身就是单例
public void say(){
}
}
扩展:多例模式
public class EmperorPlus {
private static int maxNumberOfEmperor = 3;//定义最大产生对象数
private static ArrayList<String> nameList = new ArrayList<String>();//存储每个皇帝的姓名
private static ArrayList<EmperorPlus> emperorList = new ArrayList<EmperorPlus>();//存储每个对象的实例
private static int countEmperor=0;//当前序号
//产生所有的对象
static {
for (int i = 0; i <maxNumberOfEmperor ; i++) {
emperorList.add(new EmperorPlus("皇"+(i+1)+"帝"));
}
}
private EmperorPlus() {
}
//传入皇帝姓名 建立一个皇帝对象
private EmperorPlus(String name) {
nameList.add(name);
}
public static EmperorPlus getInstance(){
Random random = new Random();
//随机拉出来一个皇帝
countEmperor=random.nextInt(maxNumberOfEmperor);
return emperorList.get(countEmperor);
}
public static void say(){
System.out.println(nameList.get(countEmperor));
}
}