JAVA设计模式之单例模式

概述

对某个类只存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

饿汉式(静态变量)

public class Singleton1 {
    public static void main(String[] args) {
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1); //true
        System.out.println(instance.hashCode()==instance1.hashCode()); //true
    }
}
/**
 * 饿汉式 (静态变量)
 */
class Singleton {
    //构造器私有化,外部不能new
    private Singleton() {

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

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

优点:

避免了线程同步问题

缺点:

在类装载的时候就完成了实例化,没有达到Lazy loading效果、并且容易造成内存浪费

饿汉式(静态代码块)

public class Singleton2 {
    public static void main(String[] args) {
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode() == instance1.hashCode()); //true
    }
}
/**
 * 饿汉式 (静态代码块)
 */
class Singleton {
    //构造器私有化,外部不能new
    private Singleton() {

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

    static { //在静态代码块中创建单例对象
        instance = new Singleton();
    }
    //提供一个共有的静态方法、返回实例对象
    public static Singleton getInstance() {
        return instance;
    }
}

优缺点与饿汉式(静态变量)类似!

懒汉式(线程不安全)

public class Singleton3 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode() == instance1.hashCode()); //true
    }
}

class Singleton {
    private static Singleton instance;

    private Singleton() {

    }
    //提供一个静态公有方法、使用到该方法才去创建
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:

调用getInstance()方法时,才创建instance实例

缺点:

若多线程情况下同时进入getInstance()if方法中,会创建多个Singleton()实例.线程不安全!

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

public class Singleton4 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode() == instance1.hashCode()); //true
    }
}
class Singleton {
    private static Singleton instance;

    private Singleton() {

    }
    //提供一个静态公有方法、使用到该方法才去创建
    //加入synchronized关键字,使得线程安全
    public  static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:

解决了线程不安全的问题

缺点:

效率低!每次调用getInstance()都要进行同步

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

public class Singleton5 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode() == instance1.hashCode()); //true
    }
}

class Singleton {
    private static Singleton instance;

    private Singleton() {

    }
    //提供一个静态公有方法、使用到该方法才去创建
    //加入synchronized关键字,使得线程安全
    public  static  Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }

直接导致线程不安全!

双重检查

public class Singleton6 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode() == instance1.hashCode()); //true
    }
}
class Singleton {
    private static volatile Singleton instance;

    private Singleton() {

    }
    //提供一个静态公有方法、加入双重检查代码、解决线程安全与懒加载问题!
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优点:

解决了线程安全、懒加载、效率的问题!

举例:

AB线程进入了if中,A创建了Singleton()实例,B再进入synchronized代码块中时,instance已经被创建,直接返回. 之后进入的线程则直接返回instance

静态内部类

public class Singleton7 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance == instance1); //true
        System.out.println(instance.hashCode() == instance1.hashCode()); //true
    }
}
//静态内部类
class Singleton {
    private Singleton() {

    }
    //写一个静态内部类,该类中由一个静态属性singleton
    private static class singletonInstance {
        private final static Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return singletonInstance.instance;
    }
}

优点:

1、调用getInstance()才去装载singletonInstance类去创建 Singleton()完成实例化.

2、JVM底层装载类的时候是线程安全的饿

2、线程安全、延迟加载、效率高

枚举

public class Singleton8 {
    public static void main(String[] args) {
        Singleton instance1 = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance1==instance2);
        System.out.println(instance1.hashCode()==instance2.hashCode());
        instance1.sayOk();
        instance2.sayOk();

    }
}
//静态内部类
enum Singleton {
    INSTANCE;
    public void sayOk() {
        System.out.println("ok");
    }
}

优点:

避免多线程同步问题、防止反序列化重新创建对象

JDK中的单例模式

Runtime采用了饿汉式:简单,类装载就创建实例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5pIVIlp-1606126127996)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201123180409600.png)]

使用场景

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nMlwJ4Nm-1606126128010)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201123180615923.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值