首页 > 其他分享 >2 单例模式

2 单例模式

时间:2023-02-25 13:24:06浏览次数:39  
标签:Singleton 模式 instance 线程 单例 null public 加载

2 单例模式
定义:确保一个类最多只有一个实例,并提供一个全局访问点

单例模式可以分为两种:预加载和懒加载

2.1 预加载
顾名思义,就是预先加载。再进一步解释就是还没有使用该单例对象,但是,该单例对象就已经被加载到内存了。

public class PreloadSingleton {

public static PreloadSingleton instance = new PreloadSingleton();

//其他的类无法实例化单例类的对象
private PreloadSingleton() {
};

public static PreloadSingleton getInstance() {
return instance;
}
}
很明显,没有使用该单例对象,该对象就被加载到了内存,会造成内存的浪费。

2.2 懒加载
为了避免内存的浪费,我们可以采用懒加载,即用到该单例对象的时候再创建。

public class Singleton {

private static Singleton instance=null;

private Singleton(){
};

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

}
}

2.3 单例模式和线程安全
(1)预加载只有一条语句return instance,这显然可以保证线程安全。但是,我们知道预加载会造成内存的浪费。

(2)懒加载不浪费内存,但是无法保证线程的安全。首先,if判断以及其内存执行代码是非原子性的。其次,new Singleton()无法保证执行的顺序性。

不满足原子性或者顺序性,线程肯定是不安全的,这是基本的常识,不再赘述。我主要讲一下为什么new Singleton()无法保证顺序性。我们知道创建一个对象分三步:

memory=allocate();//1:初始化内存空间

ctorInstance(memory);//2:初始化对象

instance=memory();//3:设置instance指向刚分配的内存地址
jvm为了提高程序执行性能,会对没有依赖关系的代码进行重排序,上面2和3行代码可能被重新排序。我们用两个线程来说明线程是不安全的。线程A和线程B都创建对象。其中,A2和A3的重排序,将导致线程B在B1处判断出instance不为空,线程B接下来将访问instance引用的对象。此时,线程B将会访问到一个还未初始化的对象(线程不安全)。

 

2.4 保证懒加载的线程安全
我们首先想到的就是使用synchronized关键字。synchronized加载getInstace()函数上确实保证了线程的安全。但是,如果要经常的调用getInstance()方法,不管有没有初始化实例,都会唤醒和阻塞线程。为了避免线程的上下文切换消耗大量时间,如果对象已经实例化了,我们没有必要再使用synchronized加锁,直接返回对象。

public class Singleton {
private static Singleton instance = null;
private Singleton() {
};
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
我们把sychronized加在if(instance==null)判断语句里面,保证instance未实例化的时候才加锁

public class Singleton {
private static Singleton instance = null;
private Singleton() {
};
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

我们经过2.3的讨论知道new一个对象的代码是无法保证顺序性的,因此,我们需要使用另一个关键字volatile保证对象实例化过程的顺序性。

public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
};
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

到此,我们就保证了懒加载的线程安全。

标签:Singleton,模式,instance,线程,单例,null,public,加载
From: https://www.cnblogs.com/zy637282/p/17154220.html

相关文章

  • 5.1 类适配器模式
    5.1类适配器模式通过多重继承目标接口和被适配者类方式来实现适配举例(将USB接口转为VGA接口),类图如下:  USBImpl的代码:publicclassUSBImplimplementsUSB{......
  • 设计模式之代理模式
    简介在某些场景下,我们需要增强某个对象的使用,比如我们在执行某个方法前加输出一条日志,但是我们不能直接改这个类,我们可以用代理对象来实现这个功能模式应用Spri......
  • java——spring boot集成RabbitMQ——topics模式——实现消费者
           ......
  • 设计模式(十五)-面向对象概念
    一、设计原则1、单一职责:设计目的单一的类。2、开放-封闭原则:对扩展开放,对修改关闭。3、里氏替换原则:子类可代替父类。4、依赖倒置:要依赖与接口,而不是具体实现,针对接口编程......
  • 6_代理模式下开发各种功能-1_多种参数传递问题
     1单个基本数据类型2多个基本数据类型3单个引用数据类型4map集合数据类型5多个引用数据类型接口packagecom.msb.mapper;importcom.msb.pojo.Emp;importorg.apache.ibati......
  • 6_代理模式下开发各种功能-1_多种参数传递问题
     1单个基本数据类型2多个基本数据类型3单个引用数据类型4map集合数据类型5多个引用数据类型接口packagecom.msb.mapper;importcom.msb.pojo.Emp;importorg.apache.ibati......
  • 18-桥接器模式
    18-桥接器模式概念桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立的变化,实现指的是抽象类和它的派生类用来实现自己的对象。实现系统可能有多角度分类,......
  • 6_代理模式下开发各种功能-1_多种参数传递问题
    ​ 1单个基本数据类型2多个基本数据类型3单个引用数据类型4map集合数据类型5多个引用数据类型接口packagecom.msb.mapper;importcom.msb.pojo.Emp;importorg......
  • 6_代理模式下开发各种功能-1_多种参数传递问题
    ​ 1单个基本数据类型2多个基本数据类型3单个引用数据类型4map集合数据类型5多个引用数据类型接口packagecom.msb.mapper;importcom.msb.pojo.Emp;importorg......
  • 学习中设计模式的总结
    首先要了解什么是设计模式呢?设计模式:可以简单的理解为两个字“经验”,就是码农们在各种需求中间,总结出来的一种最优的解法称之为设计模式;1,单例模式......