单例模式的意义:
有一些对象我们只需要一个实例,比如说线程池、缓存、对话框、日志对象、重放打印机、显卡等设备的驱动程序。这些对象只能有一个实例,否则会产生很多问题。
为了确保只有一个实例,有时我们通过全局变量的形式实现,但是将对象赋值给全局变量,但是却没有使用就会造成资源的浪费。所以还只实例化一个实例更好。

总所周知,类对象的构造函默认是public类型的,这样我就是说这个对象可以有很多实例。当然我们构造函数虽然不是公有的类型(如protected),只有同一个包的类可以实例化它时,但是仍可以实例化多次,
私有的构造函数不能被类外实例化,只能类内部实例化。但很显然不能够通过类的实例来调用构造器,因为类实例的产生和构造器的调用就像"鸡生蛋,蛋生鸡"一样, 谁先谁后说不清楚。但是如果通过类用却是可以的。可以通过调用该类的静态方法,再通过静态方法调用私有的构造函数。
单例模式确保一个类只有一个实例,并提供一个全局的访问点。

一个简单的单例模式的实现如下:

public class LazySingleton {
    //利用一个静态变量记录LazySingleton的唯一实例
    private static LazySingleton uniqueInstance;

    //把构造器声明为私有的,只有自LazySingleton类内才可以调用构造器
    private LazySingleton(){}

    //用getinstance方法实例化对象,并返回这个实例。
    public static LazySingleton singletonGetInstance() {
        if(uniqueInstance != null){
            //需要的时候就产生实例
            uniqueInstance = new LazySingleton();
        }else{
            System.out.println("already exists lazySingleton instance");
        }
        return uniqueInstance;
    }
} 

通过懒汉模式获取单例在多线程的情况是不安全的,我们可以通过对获取实例的方式进行加锁。

public static synchronizedLazySingleton singletonGetInstance() {
        if(uniqueInstance != null){
            //需要的时候就产生实例
            uniqueInstance = new LazySingleton();
        }else{
            System.out.println("already exists lazySingleton instance");
        }
        return uniqueInstance;
    }

尽管如此,这种方式只有第一次执行的时侯,才真正需要同步。一旦设置好uniqueInstance这个变量,就不再需要同步这个方法了以后的每次调用都会显得累赘。

当然如果getInstanced()的性能对应用程序不是很关键,可以什么都不做。但是要考虑加了同步的方法性能可能下降100倍那么getInstance的方法被频繁使用,可能需要慎重考虑了。
当然我们可以把同步的地方换到方法内部,如下所示:

public class UpdatedLazySingleton {
    //volatile关键词确保,当uniqueInstance变量被初始化成实例时,多个线程正确地处理uniqueInstance变量
    private volatile static UpdatedLazySingleton uniqueInstance;

    private UpdatedLazySingleton(){}

    public static UpdatedLazySingleton getInstance() {
        //检查实例,如果不存在则进入同步区块
        if(uniqueInstance == null){
            //只有第一次才彻底执行这里的代码
            synchronized (UpdatedLazySingleton.class) {
                if(uniqueInstance == null){
                    //进入区块后,再检查一次,如果仍是null,才创建实例
                    uniqueInstance = new UpdatedLazySingleton();
                }
            }
        }
        return uniqueInstance;
    }
}

这种双重检查加锁的实现方式可以大大减少getInstance()的时间消耗。

如果应用程序总是创建并使用单件实例,或者在创建和运行时方面的负担不太繁重,可能需要急切创建此单件:

public class HungrySingleton {
    private static HungrySingleton uniqueInstance = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return uniqueInstance;
    }
}

这种做法依赖JVM在加载这个类时马上创建此唯一的单件实例。JVM保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。


update_everyDay
1 声望0 粉丝