java设计模式--实现单例模式各种方式

 

一 . 懒汉模式(Lazy)

懒汉模式比较复杂,需要注意到底点很多,下面会详细介绍。懒汉模式简而言之就是用到了才去实例化对象,延迟加载。

代码如下:

class SingletonLazy {
    private static volatile SingletonLazy singletonLazy = null;
    private SingletonLazy(){}

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

singletonLazy == null

以上代码需要注意以下问题:

1. 覆盖一个private的构造方法,只提供一个单一的接口。

2. 提供一个单一的静态方法getInstance()。

3. 在创建类的地方加锁,防止多线程是创建多个对象出来,因为有可能有两个线程同时进入判断singletonLazy== null的代码块中。

4.双重锁模式。两次判断是否为null,因为初始化只有一次,所以进入该方法的大概率事件是不为空的,如果没有第一次判断就让每次多线程进来都排队判断,减少处理效率。

5. 在静态变量singletonLazy 前加volatile。volatile关键字有两个作用 1)保证可见性,2)防止指令重排序。在这里是作用2)。具体解释如下:

singletonLazy = new SingletonLazy();

以上代码,在被jvm编译器后会变成三个步骤,

1). 在堆内存区域开辟一个空间。

2). 给以上空间赋初始值。

3). 将这个空间的地址赋值给singletonTest。

因为singletonLazy = new SingletonLazy();并不是原子操作,而是被jvm编译成了以上3步。在jvm和cpu多代码进行执行时可能会对编译后的代码进行优化,对于没有依赖的代码进行指令重排,1)和2),3)之间是有依赖关系的,但是2)和3)之间是没有依赖关系的。意味着,3)可能在2)之前执行。再多线程环境中,如果线程一种的3)先执行,线程二刚好执行到if singletonLazy == null, 只是会之间返回singletonTest还有没赋初始值的对象出去。

二, 饿汉模式.

饿汉模式比较简单,简单的说就是在类初始化的时候就已经创建好对象了, 后面需要访问的对象直接去取就行了。本质上借助JVM的类加载机制,保证实例的唯一性,因为初始化只会执行一次。

代码如下:

class SingletonHungry{
    private static SingletonHungry singletonTest = new SingletonHungry();
    private SingletonHungry(){}

    public static SingletonHungry getInstance(){
        return singletonTest;
    }
}

需要注意,只有真正使用到类的时候才会导致类的初始化。以下情况会导致类的初始化:

1. 当前类是启动类,即main方法所在的类。

2. 直接对类进行new操作。

3. 访问类的静态属性,静态方法。

4. 使用反射访问类。

5. 初始化一个了的子类。

三, 内部类模式

内部类模式是目前最为推荐的一种单例模式。因为他即达到类懒加载的目的,有不用像写懒汉模式那么复杂。

class SingletonInnerClass{

    private SingletonInnerClass(){}

    public static SingletonInnerClass getInstance(){
        return InnerClass.singleton;
    }

   private static class InnerClass{
       private static final SingletonInnerClass singleton=new SingletonInnerClass ();
    }
}

知识点:

1. 一个private的构造方法,防止直接对对象的new操作。

2. 提供一个静态的唯一访问接口。

3. 一个静态内部类,该内部类的静态变量,只有在内部类被访问时候才会被被初始化。即在外边内的静态变量被初始化的时候,内部内的静态变量是不是被初始化的。

4. 和饿汉模式一样,借助jvm初始化只有一次来保证单例。

四, 枚举模式

枚举模式的本质还是饿汉模式, 在初始化枚举类的时候对静态final成员变量赋值。枚举模式的唯一优势是写起来简单,但是可读性差。

public class SingleEnumTest {
    public static void main(String [] args){
        SingltonEnum enum1= SingltonEnum.INSTANCE;
        SingltonEnum enum2= SingltonEnum.INSTANCE;
        System.out.println(enum1==enum2);
    }
}
enum SingltonEnum{
    INSTANCE;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值