设计模式:创建型-单例模式

Source


项目地址:https://gitee.com/caochenlei/design-pattern

第一章 单例模式介绍

单例模式的介绍:

单例模式(Singleton Pattern)是最简单的设计模式之一,这种类型的设计模式属于创建型模式,通过单例模式的方法创建的类在当前进程中只有一个实例。

一般情况下,不建议使用懒汉式,建议使用饿汉式。只有在要明确实现 lazy loading 效果时,才会使用登记式。如果涉及到反序列化创建对象时,可以尝试使用枚举式。如果有其他特殊的需求,可以考虑使用双检锁方式。

单例模式的优点:

  • 单例模式可以保证内存里只有一个实例,减少了内存的开销。
  • 可以避免对资源的多重占用。
  • 单例模式设置全局访问点,可以优化和共享资源的访问。

单例模式的缺点:

  • 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
  • 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
  • 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。

单例模式的场景:

  • 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
  • WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。

第二章 01-饿汉式(第一种)

描述:线程很安全,没有锁机制,执行效率高,类加载初始化,可能浪费内存。这个可以用到实际生产环境。

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

//饿汉式
class Singleton {
    
      
    //私有构造方法,防止外部new
    private Singleton() {
    
      }

    //提供一个私有的静态变量对象
    private final static Singleton instance = new Singleton();

    //向外部提供一个公开获取方法
    public static Singleton getInstance() {
    
      
        return instance;
    }
}

第三章 02-饿汉式(第二种)

描述:线程很安全,没有锁机制,执行效率高,类加载初始化,可能浪费内存。这个可以用到实际生产环境。

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

//饿汉式
class Singleton {
    
      
    //私有构造方法,防止外部new
    private Singleton() {
    
      }

    //提供一个私有的静态变量对象
    private final static Singleton instance;

    //在静态代码块中初始化该对象
    static {
    
      
        instance = new Singleton();
    }

    //向外部提供一个公开获取方法
    public static Singleton getInstance() {
    
      
        return instance;
    }
}

第四章 03-懒汉式(第一种)

描述:线程不安全,没有锁机制,执行效率高,类用时初始化,不会浪费内存。这个不建议用到实际生产环境。

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

//懒汉式
class Singleton {
    
      
    //私有构造方法,防止外部new
    private Singleton() {
    
      }

    //提供一个私有的静态变量对象
    private static Singleton instance;

    //向外部提供一个公开获取方法
    public static Singleton getInstance() {
    
      
        if (instance == null) {
    
      
            instance = new Singleton();
        }
        return instance;
    }
}

第五章 04-懒汉式(第二种)

描述:线程很安全,拥有方法锁,执行效率慢,类用时初始化,不会浪费内存。这个不建议用到实际生产环境。

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

//懒汉式
class Singleton {
    
      
    //私有构造方法,防止外部new
    private Singleton() {
    
      }

    //提供一个私有的静态变量对象
    private static Singleton instance;

    //向外部提供一个公开获取方法
    public static synchronized Singleton getInstance() {
    
      
        if (instance == null) {
    
      
            instance = new Singleton();
        }
        return instance;
    }
}

第六章 05-双检锁(推荐用)

描述:这种方式采用双检锁机制,类用时初始化,线程安全且在多线程情况下能保持高性能,实现方式略微复杂。

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

//双检锁(双重校验锁)
class Singleton {
    
      
    //私有构造方法,防止外部new
    private Singleton() {
    
      }

    //提供一个私有的静态变量对象
    private volatile static Singleton instance;

    //向外部提供一个公开获取方法
    public static Singleton getInstance() {
    
      
        if (instance == null) {
    
      
            synchronized (Singleton.class) {
    
      
                if (instance == null) {
    
      
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

第七章 06-登记式(推荐用)

描述:这种方式采用静态内部类,类用时初始化,线程安全且在多线程情况下能保持高性能,实现方式比较一般。

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

//登记式(静态内部类)
class Singleton {
    
      
    //私有构造方法,防止外部new
    private Singleton() {
    
      }

    //提供一个私有的静态内部类
    private static class SingletonHolder {
    
      
        private final static Singleton INSTANCE = new Singleton();
    }

    //向外部提供一个公开获取方法
    public static Singleton getInstance() {
    
      
        return SingletonHolder.INSTANCE;
    }
}

第八章 07-枚举式(推荐用)

描述:线程很安全,没有锁机制,执行效率高,类加载初始化,但是这种实现方式还没有被广泛采用,自动支持序列化机制,绝对防止多次实例化。

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

//枚举类
enum Singleton {
    
      
    INSTANCE
}

第九章 单例模式应用

最佳实践:java.lang.Runtime