详细的单例模式的八种写法

浅谈单例模式
最近在学设计模式,感受颇深,闲来无聊,记录一下单例模式的学习。

单例模式:采取一定的方法保证在整个软件系统中,对一个类只能存在一个对象实例,且只提供一个能取得对象实例的静态方法


单例模式的八种方式:
1)饿汉式(静态常量)
2)饿汉式(静态代码块)
3)懒汉式(线程不安全)
4)懒汉式(线程安全,同步代码块)
5)懒汉式(线程线程安全,同步方法)
6)双重检查
7)静态内部类
8)枚举
1.饿汉式,静态常量(可以使用)
优点:在类加载的时候就实例化对象,避免了多线程的同步问题
缺点:如果软件系统从始至终未使用过该实例,则造成内存浪费

public class Singleton {
    //1.提供一个私有的构造器防止new对象的实例
    private Singleton() {}
    //2.提供一个静态变量
    private static final Singleton instance = new Singleton();
    //3.提供一个静态方法获取实例
    public static Singleton getInstance(){
        return instance;
    }
}

2.饿汉式,静态代码块(可以使用)
优点和缺点跟静态常量方式一致

public class Singleton {
    private Singleton(){}
    private static Singleton instance;
    // 静态代码块,在类被加载时进行实例化
    static {
        instance = new Singleton();
    }
    // 对外提供静态方法获取实例
    public static Singleton getInstance(){
        return instance;
    }
}

3.懒汉式,线程不安全的写法(实际开发中不能使用)

public class Singleton {
    private Singleton() {
    }
    private static Singleton instance;
    // 在程序第一次需要使用时才创建实例,达到懒汉式的效果(即懒加载)
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
优点:在运行是第一次使用到该实例时才进行实例化,达到了懒加载的效果
缺点:线程不安全,在多线程情况下,如果第一个线程进入 if 后还没来得及
及往下执行,第二个线程也进入了 if 则两个线程都创建了实例。造成线程不安全

4.懒汉式,线程安全的写法(可以使用)

public class Singleton{
    private Singleton(){}
    private static Singleton instance;

    /**
     * 在程序第一次使用时进行实例化,达到懒加载效果,且进行同步,线程安全
     * 但是效率太低,每次调用时都进行加锁,实际上只需在第一次时进行加锁
     */
    public static synchronized Singleton getInstance(){
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
优点:在程序第一次使用该实例时才进行实例化,达到懒加载的效果,
缺点:效率太低,多线程情况下,每个线程都对获取实例的方法进行加锁
操纵,可能会造成阻塞。

5.懒汉式,线程不安全的写法(实际开发中不能使用)

public class Singleton {
    private Singleton() {}
    private static Singleton instance;

    /**
     * 在多线程模式下,当第一个线程进入到if里面还没来得及往下执行时,第二个线程也进入到if,会创建两个实例
     * 在实际开发中,不能使用
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}
此写法与懒加载同步方法的写法差不多,但存在线程不安全的情况,当多
线程情况下,第一个线程进入 if 后还没来得及往下执行,第二个线程也进入了
 if 只不过在同步代码块外等待,当第一个线程释放锁后,第二个线程也进入
同步代码块,也进行了实例化,系统中该类就存在多个实例。

6.双重检查(在实际开发中推荐使用)

public class Singleton{
    private Singleton(){}
    private static volatile Singleton instance;
    public static Singleton getInstance(){
    // 进行两次判断
        if (instance == null){
            synchronized (Singleton.class){
                if (instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
双重检查,实例化代码只需执行一次避免了反复进行同步
解决了懒加载的同时,避免了多线程问题的发生

7.静态内部类(推荐使用)

public class Singleton{
    // 提供私有构造器,防止被new产生新对象
    private Singleton(){}
    private static class InnerSingleton{
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance(){
        return InnerSingleton.INSTANCE;
    }

}
优点:在Sinleton类进行加载的时候不会导致静态内部类进行加载	,
从而不会使Sinleton实例化(利用了类加载机制,加载时线程时安全的
不会出现线程安全性问题。)
在调用Singleton的静态方法时导致内部类被加载才对Singleton进行实例化
达到了懒加载的效果,且在内部类进行

8.枚举(实际开发中推荐使用)

public class SingletonTest {
    public static void main(String[] args) {
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1 ==singleton2);
        System.out.println(singleton1.hashCode());
        System.out.println(singleton2.hashCode());
    }

}
enum Singleton{
    INSTANCE;
}
借助枚举来创建单例,不仅能解决多线程的问题,还能防止反序列化重新创建新的对象

单例模式记录完毕,如发现有误,望指正,谢谢。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值