单例模式学习
单例模式是Java设计模式之一,属于创建型模式。该模式的设计意图就是为了保证一个类仅有一个实例。单例模式实现方式也有很多种,下面是我在平时学习中了解到的几种单例模式模式的实现方式。
饿汉式
饿汉式实现方式,事先将类的实例创建好,然后每次访问的时候就返回创建好的实例即可。这种单例模式的实现方式是线程安全的,在类加载的时候就已经创建好了。
public class SingleClass {
private final static SingleClass singleClass = new SingleClass();
//构造函数私有化
private SingleClass() {}
public static SingleClass getSingleClass() {
return singleClass;
}
}
懒汉式(线程不安全)
懒汉式实现方式,顾名思义就是在需要这个类的实例时候才去创建,看上去比较“懒”。下面这种懒汉式实现是线程不安全的,在多线程情况下可能会出现不同的实例,没有保证类的唯一实例。在多线程情况下,A线程进入到标记1处的时候,发生了进程切换,线程B去执行发现singleClass=null
会创建对象,然后线程A获得时间片之后继续执行,会再一次创建对象。
public class SingleClass {
private static SingleClass singleClass;
//构造函数私有化
private SingleClass() {}
public static SingleClass getSingleClass() {
if (singleClass == null) {
//标记1
return new SingleClass();
}
return singleClass;
}
}
懒汉式(线程安全)
上面的懒汉式式线程不安全,会出现不同的类的实例,为了保证类的唯一实例,我们需要对上面的代码进行改造。这个改造是将获取类实例的方法上加锁,避免了上面出现的情况。但是这个实现方式也存在一些问题,我们都知道在Java中上锁是个很重的操作,比较耗时,这里每次获取实例的时候都会加锁。
public class SingleClass {
private static SingleClass singleClass;
//构造函数私有化
private SingleClass() {}
//将该方法上锁,依次来保证只有一个线程可以进入到该方法,保证了类的唯一实例
public static synchronized SingleClass getSingleClass() {
if (singleClass == null) {
return new SingleClass();
}
return singleClass;
}
}
懒汉式(双重验证方式)
针对上面出现的问题在进一步改造,避免了不必要的加锁带来的耗时问题。当对象已经被创建了后,再次调用getSingleClass()
方法的时候不用加锁了。
public class SingleClass {
private static volatile SingleClass singleClass;
//构造函数私有化
private SingleClass() {}
public static SingleClass getSingleClass() {
if (singleClass == null) {
synchronized (SingleClass.class) {
if (singleClass == null) {
singleClass = new SingleClass();
}
}
}
return singleClass;
}
}
枚举单例模式
上面几种单例模式的实现,其实都可以通过反射来破坏实例的唯一,可以多次创建类的实例,会存在安全隐患,用枚举来实现的单例模式不存在这个问题。
public enum SingleClass {
INSTANCE;
public SingleClass getInstance(){
return INSTANCE;
}
}
以上是我在学习单例模式过程中的总结,通过几种不同单例模式的实现来对比学习可以加深对单例模式的理解,在平时的面试和工作中可以根据自己的需要来实现不同方式的单例模式,希望可以帮助大家学习和理解。
有道无术,术尚可求。
有术无道,止于术。