码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式【二】—— 单例设计模式

时间:2020-06-05 22:37:08      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:loading   方式   ble   同步代码块   类装载   实例   构造器   未使用   完成   

第二章 单例设计模式

2.1 单例设计模式

采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。

2.2单例设计模式八种方式

  1. 饿汉式(静态常量)——(可以使用)
  2. 饿汉式(静态代码块)——(可以使用)
  3. 懒汉式(线程不安全)——(不要使用)
  4. 懒汉式(线程安全,同步方法)——(不推荐使用)
  5. 懒汉式(线程不安全,同步代码块)——(不能使用)
  6. 双重检查——(推荐使用)
  7. 静态内部类——(推荐使用)
  8. 枚举——(推荐使用)

2.1.1 饿汉式(静态常量)

  1. 构造器私有化(外部不能 new );
  2. 类的内部创建对象:在静态变量中;
  3. 提供一个公有的静态方法,返回实例对象。
class Singleton {
    private Singleton() { }
    private final static Singleton instance = new Singleton();
    public static Singleton getInstance() { 
        return instance;
    }
}

优缺点:

  1. 优点:这种写法比较简单,在类装载的时候就完成实例化,避免了线程同步问题。
  2. 缺点:在类装载的时候就完成实例化,没有达到 Lazy Loading 的效果,如果从始至终从未使用过这个实例,则会造成内存的浪费。
  3. 这种方式基于 classloder 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,在单例模式中大多数都是调用 getInstance 方法, 但是导致类装载的原因有很多种,因此不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 就没有达到 lazy loading 的效果。

结论:

这种单例模式可用,可能造成内存浪费。

2.1.2 饿汉式(静态代码块)

  1. 构造器私有化(防止 new );
  2. 类的内部创建对象实例:在静态代码块中,创建单例对象;
  3. 向外暴露一个静态的公共方法,返回一个实例对象。
class Singleton {
    private Singleton() { }
    private static Singleton instance;
    static { // 在静态代码块中,创建单例对象
        instance = new Singleton();
    }
    public static Singleton getInstance() { 
        return instance;
    }
}

优缺点(和上面的方法类似):

这种方式和上面的方式类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。

结论:

这种单例模式可用,但是可能造成内存浪费。

2.1.3 懒汉式(线程不安全)

提供一个静态的公有方法,当使用到该方法时,才去创建 instance

class Singleton {
    private Singleton() {}
    private static Singleton instance;
    public static Singleton getInstance() { 
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优缺点:

  1. 起到了 Lazy Loading 的效果,但是只能在单线程下使用。
  2. 如果在多线程下,一个线程进入了 if (singleton == null) 判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例,所以在多线程环境下不可使用这种方式。

结论:

在实际开发中,不要使用这种方式。

2.1.4 懒汉式(线程安全,同步方法)

提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题。

class Singleton {
    private Singleton() {}
    private static Singleton instance;
    public static synchronized Singleton getInstance() { 
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优缺点:

  1. 解决了线程安全问题。
  2. 方法进行同步效率太低,每个线程在想获得类的实例时候,执行 getInstance() 方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接 return 就行了。

结论:

在实际开发中,不推荐使用这种方式。

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

对第四种实现方式的改进,同步产生实例化的代码块。

class Singleton {
    private Singleton() {}
    private static Singleton instance;
    public static Singleton getInstance() { 
        if(instance == null) {
            synchronized (Singleton.class){
                instance = new Singleton();
            }
        }
        return instance;
    }
}

优缺点:

本意是想对第四种实现方式的改进, 但是这种同步并不能起到线程同步的作用。跟第三种实现方式遇到的情形一致,线程不安全,还是会进入到 if 语句中,会产生多个实例。

结论:

在实际开发中,不能使用这种方式。

2.1.6 双重检查

提供一个静态的公有方法,加入双重检查代码。

class Singleton {
    private Singleton() {}
    private static volatile Singleton instance; // volatile
    public static volatile Singleton getInstance() { 
        if(instance == null) {
            synchronized (Singleton.class){
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优缺点:

  1. Double-Check 概念是多线程开发中常使用到的,进行了两次 if (singleton == null) 检查,这样就可以保证线程安全了。实例化代码只用执行一次,后面再次访问时,判断 if (singleton == null),直接 return 实例化对象,也避免的反复进行方法同步。
  2. 线程安全;延迟加载;效率较高。

结论:

在实际开发中,推荐使用这种方式。

2.1.7 静态内部类

写一个静态内部类,该类中有一个静态属性 Singleton,提供一个静态的公有方法,直接返回 SingletonInstance.INSTANCE。

class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    Singleton private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static synchronized Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}

优缺点:

  1. 这种方式采用了类装载的机制来保证初始化实例时只有一个线程。
  2. 静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才会装载 SingletonInstance 类,从而完成 Singleton 的实例化。
  3. 类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。
  4. 优点:避免了线程不安全,利用静态内部类特点实现延迟加载,效率高。

结论:

推荐使用。

2.1.8 枚举

public class SingletonTest08 {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
    }
}
enum Singleton {
    INSTANCE; //属性
    public void sayOK() { 
        System.out.println("ok~");
    }
}

优缺点:

借助 JDK1.5 中添加的枚举来实现单例模式,不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

结论:

推荐使用。

设计模式【二】—— 单例设计模式

标签:loading   方式   ble   同步代码块   类装载   实例   构造器   未使用   完成   

原文地址:https://www.cnblogs.com/Songzw/p/13052560.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!