设计模式第1式--单例模式

单例模式有8种写法

  • 单例模式介绍
  • 单例的8种写法
    • 饿汉式2种
    • 懒汉式3种
    • 双重检查1种
    • 静态内部类1种
    • 枚举1种

单例模式介绍

所谓单例模式,就是采用一定方式,保证在整个系统中,对于某个类只有一个对象存在,且该类只提供一个获取对象实例的方法。

比如Hibernate的SessionFactory,他充当数据存储源的代理,并负责创建Session对象。SessionFactory并不是轻量级的,一般情况下,一个项目通常只需要一个SessionFactory就够了,这就会使用到单例模式

单例的8种写法

下面是8种写法,及每种的优缺点。其中集中饿汉式和懒汉式的优缺点,得到双重检测方式。

饿汉式2种

见如下代码

懒汉式3种

见如下代码

双重检查1种

见如下代码

静态内部类1种

见如下代码

枚举1种

见如下代码

package singleton;

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

/**
 * 饿汉式1
 * 优点:写法简单,类加载时即实例化,避免线程同步问题
 * 缺点:类加载即完成实例化,没有达到懒加载(Lazy Loading)的效果。如果自始至终从未用到这个实例,则会造成内存浪费。
 *
 * 这种单例模式可用,但是可能造成内存浪费。
 */
class Singleton1 {
    private Singleton1() {}

    private static Singleton1 instance = new Singleton1();

    public static Singleton1 getInstance() {
        return instance;
    }
}

/**
 * 饿汉式2 (静态代码块)
 *
 * 优缺点同上。
 */
class Singleton2 {
    private Singleton2() {}

    private static Singleton2 instance;

    static {
        instance = new Singleton2();
    }

    public static Singleton2 getInstance() {
        return instance;
    }
}

/**
 * 懒汉式1 (线程不安全)
 * 优点:起到懒加载的效果,但是只在单线程下使用
 * 缺点:多线程时,2个线程同时进入if判断语句,会产生多个实例。
 *
 * 实际开发中,不要使用这种方式。
 */
class Singleton3 {
    private static Singleton3 instance;

    private Singleton3() {}

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

/**
 * 懒汉式2 (线程安全,同步方法)
 * 优点:起到懒加载的效果,也解决了线程同步问题
 * 缺点:效率低,每个线程在获取类的实例时,执行getInstance()方法都要进行同步,
 * 而这个方法其实只需要执行一次实例化就够了,后面想获得该类实例,直接return就行了。
 *
 * 方法进行同步效率太低,实际开发中,不要使用这种方式。
 */
class Singleton4 {
    private static Singleton4 instance;

    private Singleton4() {}

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

/**
 * 懒汉式3 (线程不安全,同步代码块)
 *
 * 为了解决懒汉2效率低的问题,将同步操作放在new对象的地方,但是这样一来并不能保证线程安全了。
 *
 * 不推荐使用。
 */
class Singleton5 {
    private static Singleton5 instance;

    private Singleton5() {}

    public static synchronized Singleton5 getInstance() {
        if (instance == null) { // 线程不安全
            synchronized (Singleton5.class) {
                instance = new Singleton5();
            }
        }
        return instance;
    }
}

/**
 * 双重检查 (线程安全,懒加载,效率高)
 *
 * 将私有instanc加volatile关键字修饰,外加双重检查null判断,可保证线程安全,懒加载,保证效率高。
 *
 * 推荐使用。
 */
class Singleton6 {

    // volatile关键字可以使变量的改变立即生效
    private static volatile Singleton6 instance;

    private Singleton6() {}

    public static Singleton6 getInstance() {
        if (instance == null) { // 第一重检查
            synchronized (Singleton6.class) {
                if (instance == null) {  // 第二重检查
                    instance = new Singleton6();
                }
            }
        }
        return instance;
    }
}

/**
 * 静态内部类 (线程安全,懒加载)
 *
 * 利用静态内部类的特点,实现懒加载及线程安全
 *
 * 推荐使用。
 */
class Singleton7 {

    private Singleton7() {}

    // 静态内部类不会随着外部类的加载而加载,所以能够实现懒加载
    private static class SingletonInstance {
        // 内部类的静态属性只会在第一次加载类的时候初始化,jvm帮助我们保证了线程的安全性,类初始化时,别的线程时无法进入的。
        private static Singleton7 instance = new Singleton7();
    }

    // 调用此方法才会加载内部类,jvm加载类是线程安全的。
    public static Singleton7 getInstance() {
        return SingletonInstance.instance;
    }
}

/**
 * 静态内部类 (线程安全,懒加载)
 *
 * 利用静态内部类的特点,实现懒加载及线程安全
 *
 * 推荐使用。
 */
enum  Singleton8 {
    INSTANCE1; // 属性
}

/**
 * jdk中的Runtime类就是使用饿汉式单例模式
 */
class jdk {
    public long cal() {
        Runtime runtime = Runtime.getRuntime(); // 单例
        return runtime.totalMemory();
    }
}

你可能感兴趣的:(设计模式,java,设计模式,单例模式,懒汉式,饿汉式)