单例模式——个人学习

单例模式

一个类仅有一个实例,所有其他类对象共享该实例进行操作

特点:只能由自己的公共方法创建一个实例,只对外提供该唯一实例

应用场景:资源共享文件与控制资源的操作(如日志文件,应用配置,数据库连接池,线程池)

应用实例:windows task manager,数据库连接池,OS的文件系统,回收站...

实现方法:饿汉,懒汉(饱汉),双检索,静态内部类,枚举类

  • 懒汉模式只有需要单例时才去初始化实例,线程一般不安全
  • 饿汉模式在类加载阶段就将实例初始化完成,这样保证线程安全
  • 双检查模式,不是对这个方法进行synchronize,仅仅在实例化步骤前进行2次synchronize该类
  • 静态内部类,保证了线程安全,在内部类中实例化唯一实例,读取实例没有同步保证性能
  • 枚举模式,默认线程安全

相关问题:

  • clone能否产生一个新的单例模式类的实例?
    不能,单例类必须是final的不能被继承,同时假如单例类继承于有clone方法的类,需要重写clone,是它抛出异常
  • 在getInstance()方法上同步有优势还是仅同步必要的块更优优势?
    由于锁有开销,因此仅同步必要的块(创建实例部分)就行了,其他时候仅仅是对实例的只读操作,保证性能
  • 双检索有什么缺点?
    需要防止初始化实例时,指令重排序,因此最好对指定变量使用volatile修饰,防止指令重排序(jdk5.0以后引入)
  • 如何获取更多的单例对象,如何防止?
    反射机制,防止的办法就是在构造函数中判断是第几次被调用,假如不是首次调用就立即抛出异常。还有一个办法就是使用枚举类模式实现单例
Constructor con = Singleton. class. getDeclaredConstruction( ) ;
con. setAccessible( true) ;
//通过反射获取实例
Singleton instance = ( Singleton) con. newInstance( ) ;

枚举类型

  • 用来表示常量,作为switch的选择类型,继承自java.lang.Enum,因此不能继承其他类
  • 在类中添加其他方法,方法必须在实例后面,最后一个实例后需要接";"
  • 枚举集合:java.util.EnumSet,java.util.EnumMap

实现方法实践

//单例模式的实现方式

// 懒汉(饱汉),一般没有对方法同步,多线程可能存在生成多个实例,优点是效率高,但是不安全,
// 有时候直接类加载就初始化静态变量,浪费内存
class Singleton{ 
    private static Singleton singleton;
    private Singleton(){};

    public static Singleton getInstance(){
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

//饿汉,类加载就产生实例
class Singleton{ 
    private static Singleton singleton = new Singleton();
    private Singleton(){};

    public static synchronized Singleton getInstance(){
        return singleton;
    }
}

//双重检测,对实例化块进行2次检验,使用同步
class Singleton{ 
    private static volatile Singleton singleton;
    private Singleton(){};

    public static Singleton getInstance(){
        if(singleton == null){
            synchronized(Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

//静态内部类,不用使用同步,线程安全.内部类私有性质保证只有getInstance能够调用它
class Singleton{ 
    
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    } 

    private Singleton(){};

    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

//枚举类,默认线程安全,这种方式绝对防止反射调用私有构造器来破坏单例
public enum Singleton{
    INSTANCE;

    private String name;

    public void dosomething(){
        doing...
    }
}

你可能感兴趣的:(单例模式——个人学习)