java设计模式-单例模式

一、概念

确保只生成一个实例对象的模式叫做单例模式

二、实现方式

1.静态变量初始化的方式(饿汉模式)常用

public class Singleton {
    //声明为private只可以内部使用;
    //声明为static在类初次加载时调用构造函数初始化,确保仅初始化一次
    private static Singleton ourInstance = new Singleton();
    //声明为private的构造函数只可内部调用
    private Singleton() {
        System.out.println("Singleton生成一个实例");
    }
    //声明public static,可以外部使用类名调用获取实例
    public static Singleton getInstance() {
        return ourInstance;
    }
}

2. 静态变量初始化的方式(饿汉模式)不常用(因为外部使用是使用Singleton.INSTANCE获取,不能屏蔽内部生成对象的实现,例如以后想修改为懒汉模式,调用方也需要修改)

public class Singleton {
    //public修饰供外部直接使用类名获取
    //static在类加载时调用new Singleton()初始化
    //final 防止外部赋值覆盖
    public final static Singleton INSTANCE = new Singleton();

    private Singleton(){
        System.out.println("Singleton生成一个实例");
    }
}

3.获取时方法内初始化(懒汉模式)不常用(存在性能问题,因为每次获取单例对象都受到synchronized限制,需排队)

public class Singleton {
    //类加载初始化为null
    private static Singleton singleton;
    //声明为private的构造函数只可内部调用
    private Singleton(){
        System.out.println("Singleton生成一个实例");
    }
    //声明public static,可以外部使用类名调用获取实例
    //使用synchronized关键字确保多线程情况下也仅生成一个对象
    public static synchronized Singleton getInstance(){
        if(singleton == null){
            //判断singleton为空时,生成对象
            singleton = new Singleton();
        }
        return singleton;
    }
}

4.获取时方法内初始化(属于上一个单例模式写法的优化版,修改了synchronized的作用范围)(懒汉模式)常用

public class Singleton {
    
    //类加载初始化为null
    private static Singleton singleton;
    
    //声明为private的构造函数只可内部调用
    private Singleton(){
        System.out.println("Singleton生成一个实例");
    }
    public static Singleton getInstance(){
        //第一次判断singleton是否为空,防止大部分方法请求进入synchronized代码块
        if(singleton == null){
            synchronized (Singleton.class) {
                //第二次判断singleton是否为空,是为了防止多线程情况下,第一次判断均通过后,排队进入静态代码块,多次创建对象
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

5.内部类初始化(懒汉模式)常用

public class SingletonInner {
    //声明为private的构造函数只可内部调用,内部类也可以调用
    private SingletonInner() {
        System.out.println("SingletonInner生成一个实例");
    }
    //声明public static,可以外部使用类名调用获取实例
    public static SingletonInner getInstance() {
        //返回内部类持有的INSTANCE(此时加载内部类)
        return SingletonIn.INSTANCE;
    }
    //定义private内部类,外部不可见,在内部类加载时,初始化INSTANCE,类加载机制确保了线程安全
    private static class SingletonIn{
        private static final SingletonInner INSTANCE = new SingletonInner();
    }
}

 三、错误示范

1.未使用private修饰构造函数

/**
 * 这里不关注生成方式(饿汉、懒汉),所以选择了比较简便的写法
 */
public class SingletonErr {

    private static SingletonErr singleton = new SingletonErr();

    public static SingletonErr getInstance(){
        return singleton;
    }
}

外部可以使用new关键字生成 SingletonErr的对象,违背了单例模式的概念

2.存在线程安全问题

/**
 * 懒汉模式这以下写法存在线程安全问题
 */
public class SingletonErr {

    private static SingletonErr singleton;

    private SingletonErr(){
        System.out.println("SingletonErr生成一个实例");
    }

    //多线程并发首次获取时,可能会创建多个实例
    public static SingletonErr getInstance1(){
        if(singleton == null){
            singleton = new SingletonErr();
        }
        return singleton;
    }

    //多线程并发首次获取时,判断对象为空这块可能会同时通过,创建对象虽加了synchronized,但不能防止通过空校验的线程多次创建实例
    public static SingletonErr getInstance2(){
        if(singleton == null){
            synchronized (SingletonErr.class){
                singleton = new SingletonErr();
            }
        }
        return singleton;
    }
}

多线程时,调用getInstance1或者getInstance2可能返回不同的对象,违背了单例模式的概念

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值