单例模式(1/23)

这样理解应该过更好一点:

自从秦始皇确立了皇帝这个位置以后,同一时期基本上就只有一个人孤零零地坐在这个
位置。这种情况下臣民们也好处理,大家叩拜、谈论的时候只要提及皇帝,每个人都知道指
的是谁,而不用在皇帝前面加上特定的称呼,如张皇帝、李皇帝。这一个过程反应到设计领
域就是,要求一个类只能生成一个对象(皇帝),所有对象对它的依赖都是相同的,因为只
有一个对象,大家对它的脾气和习性都非常了解,建立健壮稳固的关系,我们把皇帝这种特
殊职业通过程序来实现。
皇帝每天要上朝接待臣子、处理政务,臣子每天要叩拜皇帝,皇帝只能有一个,也就是
一个类只能产生一个对象,该怎么实现呢?对象产生是通过new关键字完成的(当然也有其
他方式,比如对象复制、反射等),这个怎么控制呀,但是大家别忘记了构造函数,使用
new关键字创建对象时,都会根据输入的参数调用相应的构造函数,如果我们把构造函数设
置为private私有访问权限不就可以禁止外部创建对象了吗?臣子叩拜唯一皇帝的过程类图如

首先,在高并发情况下,请注意单例模式的线程同步问题。单例模式有几种不同的实现
方式,上面的例子不会出现产生多个实例的情况,但是如代码清单7-4所示的单例模式就需
要考虑线程同步。
代码清单7-4 线程不安全的单例
public class Singleton {
private static Singleton singleton = null;
//限制产生多个对象
private Singleton(){
}
//通过该方法获得实例对象
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
该单例模式在低并发的情况下尚不会出现问题,若系统压力增大,并发量增加时则可能
在内存中出现多个实例,破坏了最初的预期。为什么会出现这种情况呢?如一个线程A执行
到singleton = new Singleton(),但还没有获得对象(对象初始化是需要时间的),第二个线程
B也在执行,执行到(singleton == null)判断,那么线程B获得判断条件也是为真,于是继续
运行下去,线程A获得了一个对象,线程B也获得了一个对象,在内存中就出现两个对象!
解决线程不安全的方法很有多,可以在getSingleton方法前加synchronized关键字,也可以
在getSingleton方法内增加synchronized来实现,但都不是最优秀的单例模式,建议读者使用如
代码清单7-3所示的方式(有的书上把代码清单7-3中的单例称为饿汉式单例,在代码清单7-4
中增加了synchronized的单例称为懒汉式单例)。
其次,需要考虑对象的复制情况。在Java中,对象默认是不可以被复制的,若实现了
Cloneable接口,并实现了clone方法,则可以直接通过对象复制方式创建一个新对象,对象
复制是不用调用类的构造函数,因此即使是私有的构造函数,对象仍然可以被复制。在一般
情况下,类复制的情况不需要考虑,很少会出现一个单例类会主动要求被复制的情况,解决
该问题的最好方法就是单例类不要实现Cloneable接口。

当皇帝不止一个的时候:

package SingleP;

import java.util.ArrayList;
import java.util.Random;

public class Emperor {
    public static int Max = 2;
    private static ArrayList<String> nameList = new ArrayList<String>();
    private static ArrayList<Emperor> empList = new ArrayList<Emperor>();
    private static int countNum = 0;
    static {
        for(int i=0;i<Max;i++){
            empList.add(new Emperor("king"+(i+1)));
        }
    }
    private Emperor(){
    }
    private Emperor(String empName){
        nameList.add(empName);
    }
    public static Emperor getInstance(){
        Random random = new Random();
        countNum = random.nextInt(Max);
        return empList.get(countNum);
    }
    public static void say(){
        System.out.println(nameList.get(countNum));
    }
}
package SingleP;

public class MinisterD {
    public static void main(String[] args){
        int minister = 5;
        for(int i =0;i<minister;i++){
            Emperor emperor = Emperor.getInstance();
            System.out.println(i+"pin visit");
            emperor.say();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zy1104560031/article/details/83313320