懒汉式单例模式,是在程序需要用到该实例时才会创建的。这样就不会像饿汉式一样,在类加载过程中就会创建。这样就减少了内存的浪费,当然也自然而然的带来了一些缺点:需要时才创建,影响程序的执行效率。另外,懒汉式单例模式在使用时进行创建,势必会带来线程安全的问题,需要解决以上问题,就需要用到锁。锁的使用也在一定程度上会带来一定的执行效率问题。
第一种:普通的懒汉式单例模式
直接上代码:
public class LazySingleton {
private LazySingleton() {
}
private volatile static LazySingleton instance;
public synchronized static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
这种设计明显的一个问题就是执行效率低,无论是否已经存在实例,在多线程的情况下都会发生阻塞。
对以上代码进行改进,首先让当程序中实例存在的时候,直接返回实例,不需要抢占锁。当程序中不存在实例时,再抢占锁进行创建。根据以上的思想,出现了第二种懒汉式方式:
第二种:双重判断型单例模式
public class LazyDoubleCheckSingleton {
private LazyDoubleCheckSingleton() {
}
private volatile static LazyDoubleCheckSingleton instance;
public static LazyDoubleCheckSingleton getInstance() {
//确定是否需要阻塞
if (instance == null) {
synchronized (LazyDoubleCheckSingleton.class) {
//确定是否需要创建实例
if (instance == null) {
//这里在多线程的情况下会出现指令重排的问题,所以对共有资源instance使用关键字volatile修饰
instance = new LazyDoubleCheckSingleton();
}
}
}
return instance;
}
}
对于第二种方式,较第一种方式而言,性能提高了。但是代码的可读性差了。
第三种:利用java语法本身特性
public class LazyStaicSingleton {
private LazyStaicSingleton(){}
public static LazyStaicSingleton getInstance(){
return Hander.INSTANCE;
}
private static class Hander{
private static final LazyStaicSingleton INSTANCE=new LazyStaicSingleton();
}
}
针对以上三种方式,都可以通过反射破坏其单例模式的特性,这个时候可以在私有构造方法种如下设计:
private LazyStaicSingleton(){
if(Hander.INSTANCE!=null){
throw new RuntimeException("不允许非法访问");
}
}
这样在通过反射创建实例时就会报错。
测试代码如下:
public class LazyStaticSingletonTest {
public static void main(String[] args) {
//先创建一个实例
LazyStaicSingleton instance=LazyStaicSingleton.getInstance();
System.out.println(instance);
//通过反射创建实例
try{
Class<?> clazz=LazyStaicSingleton.class;
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object lazyStaicSingleton=c.newInstance();
}catch (Exception e){
e.printStackTrace();
}
}
}
结果:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.example.singleton.LazyStaticSingletonTest.main(LazyStaticSingletonTest.java:17)
Caused by: java.lang.RuntimeException: 不允许非法访问
at com.example.singleton.lazy.LazyStaicSingleton.<init>(LazyStaicSingleton.java:6)
... 5 more
以上就是极悦小编介绍的"三种懒汉式单例模式",希望对大家有帮助,如有疑问,请在线咨询,有专业老师随时为您务。
你适合学Java吗?4大专业测评方法
代码逻辑 吸收能力 技术学习能力 综合素质
先测评确定适合在学习