单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为,比如:全局信息配置。
【面试题】
单例模式的思想是什么?写一个代码体现。
(我们最好写懒汉式的单例模式给面试官,这个才是他想要的答案)
开发使用:恶汉式(是不会出问题的单例模式)
面试时写:懒汉式(可能会出现问题的单例模式)
A. 懒汉式(延迟加载)
B. 线程安全问题
a. 是否多线程环境–是
b. 是否有共享数据–是
c. 是否有多条语句操作共享数据–是
零、单例模式的一般步骤
- 私有化构造方法使其外部不能直接创建对象保证对象的唯一性
- 私有化和静态化自己内部的对象(因为外部不能new对象只能内部来new了)
- 提供一个公共的静态的方法给外部直接使用自己内部创建的对象
一、饿汉式
饿汉式是最简单的实现方式,这种实现方式适合那些在初始化时就要用到单例的情况,这种方式简单粗暴,如果单例对象初始化非常快,而且占用内存非常小的时候这种方式是比较合适的,可以直接在应用启动时加载并初始化。
// 单例模式最简单的实现:
public class Singleton{
// 由私有构造方法和static来确定唯一性。
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton newInstance(){
return instance;
}
}
饿汉式有个致命缺点:何时产生实例不好控制。虽然我们知道,在类Singleton第一次被加载的时候,就产生了一个实例。但是如果这个类中有其他属性,如下代码:
public class Singleton {
private static Singleton instance = new Singleton();
public static int STATUS=1;
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
当使用
System.out.println(Singleton.STATUS);
这个实例就被产生了。也许此时你并不希望产生这个实例。如果系统特别在意这个问题,这种单例的实现方法就不太好。
还有一个“但是”,如果单例初始化的操作耗时比较长而应用对于启动速度又有要求,或者单例的占用内存比较大,再或者单例只是在某个特定场景的情况下才会被使用,而一般情况下是不会使用时,使用饿汉式的单例模式就是不合适的,这时候就需要用到懒汉式的方式去按需延迟加载单例。
二、懒汉式
懒汉式与饿汉式的最大区别就是将单例的初始化操作,延迟到需要的时候才进行,这样做在某些场合中有很大用处。比如某个单例用的次数不是很多,但是这个单例提供的功能又非常复杂,而且加载和初始化要消耗大量的资源,这个时候使用懒汉式就是非常不错的选择。
public class Singleton{
private static Singleton instance = null;
private Singleton(){}
// 此方法实现的单例,无法在多线程中使用,多线可以同时进入if方法,会导致生成多个单例对象。
public static Singleton getInstance(){
if(null == instance){
instance =