单例模式8种写法及分析

最近复习了下单例模式写法,记录下来,分析每种优缺点

其中标红的是推荐方式,有双重检查模式,还有枚举模式

1.饿汉式  静态变量方式(可用)

* 优点:编写简单 不存在并发问题 多个线程创建多个实例
* 缺点:一开始就加载,浪费资源.

/**
 * @author: xuxu
 * @date 2020/2/2 16:08
 * @Description: 第一种单例模式写法
 * 饿汉式  静态变量方式(可用)
 * 优点:编写简单 不存在并发问题 多个线程创建多个实例
 * 缺点:一开始就加载,浪费资源.
 */
public class Singleton01 {
    private static Singleton01 INSTANCE = new Singleton01();

    private Singleton01(){};

    public static Singleton01 instance(){
        return INSTANCE;
    }

    //测试
    public static void main(String[] args) {
        System.out.println(Singleton01.instance());
        System.out.println(Singleton01.instance());

    }
}

2.饿汉式 静态块模式(可用)

优点缺点和第一种类似 只是写法不同
/**
 * @author: xuxu
 * @date 2020/2/2 16:12
 * @Description: 第二种单例模式创建方式
 * 饿汉式 静态块模式(可用)
 * 优点缺点和第一种类似 只是写法不同
 */
public class Singleton02 {
    private static Singleton02 INSTANCE;

    //静态块中创建
    static{
        INSTANCE = new Singleton02();
    }

    private Singleton02 (){

    }

    public static Singleton02 instance(){
        return INSTANCE;
    }

    public static void main(String[] args) {
        System.out.println(Singleton02.instance());
        System.out.println(Singleton02.instance());
    }
}

3.懒汉式 (不可用)

* 优点:懒加载,节省内存 使用时才实例化
* 缺点:存在线程安全问题,如果多个线程同时创建 很有可能出现同时判断INSTANCE为空 然后创建多个实例的情况
/**
 * @author: xuxu
 * @date 2020/2/2 16:16
 * @Description:
 *
 * 第三种方式
 * 懒汉式 (不可用)
 * 优点:懒加载,节省内存 使用时才实例化
 * 缺点:存在线程安全问题,如果多个线程同时创建 很有可能出现同时判断INSTANCE为空 然后创建多个实例的情况
 */
public class Singleton03 {
    private static Singleton03 INSTANCE;

    private Singleton03(){};

    public static Singleton03 instance(){
        if(INSTANCE==null){
            INSTANCE = new Singleton03();
        }
        return INSTANCE;
    }
}

4.懒汉式 同步锁(可用)

* 优点:懒加载,用synchronized关键字修饰 避免线程安全问题
* 缺点:每次调用该方式获取实例都会加锁,性能上有影响
/**
 * @author: xuxu
 * @date 2020/2/2 16:20
 * @Description:
 * 第4种创建方式  懒汉式 同步锁(可用)
 * 优点:懒加载,用synchronized关键字修饰 避免线程安全问题
 * 缺点:每次调用该方式获取实例都会加锁,性能上有影响
 */
public class Singleton04 {
    private static Singleton04 INSTANCE;

    private Singleton04(){};

    public static synchronized Singleton04 instance(){
        if(INSTANCE==null){
            INSTANCE = new Singleton04();
        }
        return INSTANCE;
    }

}

5.懒汉式 同步锁(不可用)

* 优点:懒加载,每次调用该方式获取实例前先判断是否实例已经存在,不存在才加锁
* 缺点:虽然创建时加了锁,但是前面的判断同样存在并发问题 比如两个线程都通过了判断.然后再获取锁
/**
 * @author: xuxu
 * @date 2020/2/2 16:20
 * @Description:
 * 第5种创建方式  懒汉式 同步锁(不可用)
 * 优点:懒加载,每次调用该方式获取实例前先判断是否实例已经存在,不存在才加锁
 * 缺点:虽然创建时加了锁,但是前面的判断同样存在并发问题 比如两个线程都通过了判断.然后再获取锁
 */
public class Singleton05 {
    private static Singleton05 INSTANCE;

    private Singleton05(){};

    public static Singleton05 instance(){
        if(INSTANCE==null){
            synchronized(Singleton05.class){
                INSTANCE = new Singleton05();
            }
        }
        return INSTANCE;
    }

}

6.懒汉式 双重检查模式 (面试时推荐用)

* 优点:懒加载,不存在线程安全问题
* 缺点:编写代码复杂,volatile容易遗漏
/**
 * @author: xuxu
 * @date 2020/2/2 16:20
 * @Description:
 * 第6种创建方式  懒汉式 双重检查模式 (面试时推荐用)
 * 优点:懒加载,不存在线程安全问题
 * 缺点:编写代码复杂,volatile容易遗漏
 */
public class Singleton06 {
    //这里强调必须要加volatile
    // 避免new Singleton06()创建对象时出现指令重排.
    // 创建对象分3步,1.创建空对象,内存中分配地址 2.对象初始化赋值  3.对象实例指向对象引用. 这3部可能发生重排序
    // 导致13步先执行,导致实际返回的INSTANCE内部属性没有初始化
    private volatile static Singleton06 INSTANCE;

    private Singleton06(){};

    public static Singleton06 instance(){
        if(INSTANCE==null){
            synchronized(Singleton06.class){
                //第二次检查,避免上一次判断存在线程安全问题.
                if(INSTANCE==null){
                    INSTANCE = new Singleton06();
                }
            }
        }
        return INSTANCE;
    }

}

7.静态内部类方式(可用)

/**
 * @author: xuxu
 * @date 2020/2/2 16:20
 * @Description:
 * 第7种创建方式  静态内部类方式(可用)
 * 内部类的特点:
 * 1.只能在内部类中定义静态类
 * 2.静态内部类与外层类绑定,即使没有创建外层类的对象,它一样存在。
 * 3.静态类的方法可以是静态的方法也可以是非静态的方法,静态的方法可以在外层通过静态类调用,而非静态的方法必须要创建类的对象之后才能调用。
 * 5.只能引用外部类的static成员变量(也就是类变量)。
 * 6.如果一个内部类不是被定义成静态内部类,那么在定义成员变量或者成员方法的时候,是不能够被定义成静态的。
 * 优点:
 * 缺点:
 */
public class Singleton07 {

    private Singleton07(){};

    private static class InnerSingleton{
        private static Singleton07 INSTANCE = new Singleton07();
    }

    public static Singleton07 instance(){
        return InnerSingleton.INSTANCE;
    }

    public static void main(String[] args) {
        Singleton07 instance =  InnerSingleton.INSTANCE;
    }
}

8.枚举(最好的方法)

* 优点:
* 我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的
* 1.代码简洁
* 2.可以防止反射破坏单例模式
* 3.线程安全
/**
 * @author: xuxu
 * @date 2020/2/2 17:43
 * @Description: 枚举(最好的方法)
 * 优点:
 * 我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的
 * 1.代码简洁
 * 2.可以防止反射破坏单例模式
 * 3.线程安全
 */
public enum Singleton08 {
    //单例实例
    INSTANCE;

    /**
     * 工具类中的方法
     */
    public void whateverMethod(){
        System.out.println("工具类方法");
    }

    public static void main(String[] args) {
        Singleton08.INSTANCE.whateverMethod();
    }
}
发布了229 篇原创文章 · 获赞 49 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/baiyan3212/article/details/104158989