单例模式

目录

单例模式:

单例模式的8种写法:

1、饿汉式(静态常量)

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

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

4、懒汉式(线程安全,同步方法,不推荐使用)

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

6、双重检查(推荐使用)

7、静态内部类(推荐使用)

8、枚举(推荐使用)

JDK中单例模式的使用

单例模式的注意事项


单例模式:

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

 

单例模式的8种写法:

1、饿汉式(静态常量)

Java代码

/**
 * 单例模式第一种写法  饿汉式(静态常量)
 *
 * @author wjh
 * @date 2020-06-08 13:30
 */
public class Singleton1 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        // 测试是否是同一个实例对象
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}

class Singleton {
    // 1、 私有化构造器
    private Singleton() {

    }

    // 2、本类内部创建对象实例
    private final static Singleton instance = new Singleton();

    // 3、提供一个公有的静态方法,返回实例
    public static Singleton getInstance() {
        return instance;
    }
}

 

优点:

  • 写法简单
  • 在类加载时就实例化,没有线程安全问题

缺点:

  • 由于在类加载时就创建对象,没有达到懒加载的效果,如果没有用到这个实例,那么会造成内存浪费

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

Java代码

/**
 * 单例模式第二种写法  饿汉式(静态代码块)
 *
 * @author wjh
 * @date 2020-06-08 13:44
 */
public class Singleton2 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        // 测试是否是同一个实例对象
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}

class Singleton {
    // 1、 私有化构造器
    private Singleton() {

    }

    // 2、本类内部创建对象实例
    private static Singleton instance;

    static {
        // 在静态代码块中创建实例对象
        instance = new Singleton();
    }

    // 3、提供一个公有的静态方法,返回实例
    public static Singleton getInstance() {
        return instance;
    }
}

优缺点与第一种写法相同


3、懒汉式(线程不安全

Java代码

/**
 * 单例模式第3种写法(线程不安全)
 * @author wjh
 * @date 2020-06-08 13:55
 */
public class Singleton3 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        // 测试是否是同一个实例对象
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
}

class Singleton {
    // 私有化构造器
    private Singleton() {

    }

    private static Singleton singleton;

    // 提供静态公有方法,当调用到方法时,才会去创建实例对象
    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

该方法只能在单线程模式下使用,多线程会出现线程安全问题

原因:多线程下,当一个线程进入if (singleton == null)后,还未执行后续代码,cpu切换到线程2,线程2也进入了 if (singleton == null),这样会new出多个实例,就不是单例模式了


4、懒汉式(线程安全,同步方法,不推荐使用

Java代码

/**
 * 单例模式第3种写法(线程安全,同步方法)
 *
 * @author wjh
 * @date 2020-06-08 14:06
 */
public class Singleton4 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

class Singleton {
    // 私有化构造器
    private Singleton() {

    }

    private static Singleton singleton;

    // 使用synchronized加锁,使方法线程安全
    public synchronized static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

优点:

  • 实现懒加载
  • 解决了线程安全问题

缺点:

  • 并发效率低(synchronized锁的粒度大,锁方法) ,本质上只要确保第一次实例化不发生线程安全问题就可以了,后续只是获取实例,不会发生线程安全问题

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

Java代码

/**
 * 单例模式第5种写法(线程不安全,同步代码块)
 *
 * @author wjh
 * @date 2020-06-08 14:06
 */
public class Singleton5 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

class Singleton {
    // 私有化构造器
    private Singleton() {

    }

    private static Singleton singleton;

    public static Singleton getInstance() {
        if (singleton == null) {
            // 同步代码块(没有实际作用,还是会出现线程安全问题)
            synchronized (Singleton.class) {
                singleton = new Singleton();
            }
        }
        return singleton;
    }
}

原因:多线程下,当一个线程进入if (singleton == null)后,还未执行后续代码,cpu切换到线程2,线程2也进入了 if (singleton == null),就算有synchronized,这2个线程还是会创建出新的实例


6、双重检查(推荐使用)

Java代码

/**
 * 单例模式第6种写法 双重检查  推荐使用
 *
 * @author wjh
 * @date 2020-06-08 14:06
 */
public class Singleton6 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

class Singleton {
    // 私有化构造器
    private Singleton() {

    }

    private static Singleton singleton;

    public static Singleton getInstance() {
        if (singleton == null) {
            // 同步代码块
            synchronized (Singleton.class) {
                // 再次检查是否创建过实例
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

优点:

  • 保证了并发效率
  • 解决了线程安全问题
  • 实现了懒加载

7、静态内部类(推荐使用)

Java代码

/**
 * 单例模式第7种写法 静态内部类
 *
 * @author wjh
 * @date 2020-06-08 14:06
 */
public class Singleton7 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

class Singleton {
    // 私有化构造器
    private Singleton() {

    }

    // 静态内部类(在外部类加载时,是不会加载静态内部类的)
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        // 直接使用SingletonInstance时,JVM才会去加载SingletonInstance类(实现了懒加载)
        return SingletonInstance.INSTANCE;
    }
}

优点:

  • 利用JVM的类加载是线程安全的,解决线程安全问题

  • 利用了静态内部类懒加载的机制,实现了实例的懒加载


8、枚举(推荐使用)

Java代码

/**
 * 单例模式第8种写法 枚举实现单例模式
 *
 * @author wjh
 * @date 2020-06-08 14:38
 */
public class Singleton8 {
    public static void main(String[] args) {
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
        instance.sayOK();
    }
}

enum Singleton {
    INSTANCE; // 属性

    public void sayOK() {
        System.out.println("OK");
    }
}

优点:

  • 借助枚举是天然的单例,来实现单例

JDK中单例模式的使用

Runtime类:使用饿汉式的单例模式

单例模式_第1张图片


单例模式的注意事项

  • 单例模式保证了系统内存中只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 获取单例对象时,不是使用new,而是调用对应的方法获取
  • 单例模式的使用场景:需要频繁的进行创建和销毁的对象,创建对象时耗时过多或耗费资源过多,但又不常用的对象、工具类对象、频繁访问数据库或文件的对象(如数据源、session工厂等)

 

你可能感兴趣的:(设计模式)