当前位置:   article > 正文

`懒汉`,`饿汉`!!! 快来看单例模式的8种实现_饿汉式有哪些实现方式

饿汉式有哪些实现方式

1.什么是单例模式

设计模式一共有23种,分为3种类型

  1. 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。

  2. 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。

  3. 行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。

单例模式是一种创建型的设计模式,单例模式保证了一个类在内存中只有一份实例对象,并且该类只提供一个静态方法来获取该对象;

2.单例模式的8种实现

(1)饿汉式(静态常量)
(2)饿汉式(静态代码块)

(3)懒汉式(线程不安全)
(4)懒汉式(同步方法)
(5)懒汉式(同步代码块)

(6)双重检查
(7)静态内部类
(8)枚举

(1)饿汉式(静态常量)

  1. 构造器私有化 (防止 new )
  2. 类的内部创建对象
  3. 向外暴露一个静态的公共方法。getInstance
// 单例模式 ---- 饿汉式
class SingleType{

    private final static SingleType instance = new SingleType();

    private SingleType(){

    }

    public static SingleType getInstance(){
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(2)饿汉式(静态代码块)

// 单例模式 ---- 饿汉式
class SingleType1{

    private final static SingleType1 instance;

    private SingleType1(){

    }
    static {
        instance = new SingleType1();
    }

    public static SingleType1 getInstance(){
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

前两种都是饿汉式的实现
一种静态代码块,一种是静态成员变量,他们都是在类加载的时候就已经实例化好了对象
优点: 线程安全,因为在类加载的时候,就已经创建了实例对象,不同线程去访问,得到的都是同一个对象
缺点:是不能延迟加载,容易造成内存浪费,因为我们知道调用静态方法会加载方法所在的类,如果我们调用的不是创建该对象的静态方法,这时类就会被加载,从而对象就会被创建,然而这时我们可能还并不想创建对象;

(3)懒汉式(线程不安全)

class SingleType1{
    
    private static  SingleType1 instance ;

    private SingleType1(){

    }
    public static SingleType1 getInstance(){
        if (instance == null){
            instance = new SingleType1();
        }
        return instance;
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

1.实现了懒加载
2.线程不安全,会创建对个实例对象

(4)懒汉式(同步方法)

class SingleType1{
    
    private static  SingleType1 instance ;

    private SingleType1(){

    }
    public static synchronized  SingleType1 getInstance(){
        if (instance == null){
            instance = new SingleType1();
        }
        return instance;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

1,解决了线程安全问题
2.也实现了懒加载
3.但是效率不高,每个线程想去获取对象时,都会上锁,其实getInstance方法本需要执行一次就够了

(5)懒汉式(同步代码块, 线程不安全)

class SingleType1{

    private static  SingleType1 instance ;

    private SingleType1(){

    }
    public  static   SingleType1 getInstance(){
       
            if (instance == null){
                synchronized (SingleType1.class){
                instance = new SingleType1();
            }
        }
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

线程不安全,不推荐使用

(6)双重检查

class SingleType06{
    private static volatile SingleType06 instance;
    private SingleType06(){

    }
    public static SingleType06 getInstance(){
        if (instance == null){
            synchronized (SingleType06.class){
                if (instance == null){
                    instance = new SingleType06();
                }
            }
        }
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

1.解决线程安全问题
2.解决懒加载问题(用到时才加载)
3.保证了效率,避免反复进行方法同步
开发中推荐这种模式

(7)静态内部类

public class SingleTypeTest07 {
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
          singleType07 instance1 = singleType07.getInstance();
            System.out.println(instance1.hashCode());
        },"t1").start();

        new Thread(()->{
            singleType07 instance2 = singleType07.getInstance();
            System.out.println(instance2.hashCode());
        },"t2").start();
    }
}


//方法时,才会加载SingelInstance静态内部类
class singleType07{
    private singleType07(){

    }
    private static class SingelInstance{
       private static final singleType07 INSTANCE = new singleType07();
    }

    public static singleType07 getInstance(){
        return SingelInstance.INSTANCE;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

//好处:
1.保证了线程安全:在加载类时,JVM底层的类加载器保证线程安全
2.保证了懒加载:在在加载singleType07类的时候不会加载SingelInstance类,只有在调用getInstance方法时,才会加载SingelInstance静态内部类
(8)枚举

public class SingleTypeTest08 {
    public static void main(String[] args) {
        singleTon instance = singleTon.INSTANCE;
        singleTon instance1 = singleTon.INSTANCE;
        System.out.println(instance == instance1);
    }
}


enum singleTon{
    INSTANCE
    // 等价于 public static final singleTon instance = new singleTon();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 用枚举实现单例模式
  • 1,不仅能避免多线程同步问题,而且能防止反序列化重新创建对象
  • 2.这种方式是 Effective Java 作者 Josh Bloch 提倡的方式

3.单例模式的适用场合

1. 需要频繁的进行创建和销毁的对象、
2. 创建对象时耗时过多或耗费资源过多(即:重量级对象)
3. 经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session 工厂等)

4.单例模式在JDK源码中的体现

在Runtime类中就使用了单例模式(饿汉式)
源码:

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}

.........
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/157701
推荐阅读
相关标签
  

闽ICP备14008679号