java单例模式精解
Java单例模式详解
从这里再来总结单例模式的特点:首先,单例模式使类在程序生命周期的任何时刻都只有一个实例,然后,单例的构造函数是私有的,外部程序如果想要访问这个单例类的话,必须通过GetInstance()来请求(注意是请求)得到这个单例类的实例。
有的时候,总是容易把全局变量和单例模式给弄混了,下面就剖析一下全局变量和单例模式相比的缺点首先,全局变量呢就是对一个对象的静态引用,全局变量确实可以提供单例模式实现的全局访问这个功能,但是,它并不能保证您的应用程序中只有一个实例,同时,在编码规范中,也明确指出,应该要少用全局变量,因为过多的使用全局变量,会造成代码难读,还有就是全局变量并不能实现继承(虽然单例模式在继承上也不能很好的处理,但是还是可以实现继承的)而单例模式的话,其在类中保存了它的唯一实例,这个类,它可以保证只能创建一个实例,同时,它还提供了一个访问该唯一实例的全局访问点。
上面呢,差不多就将单例模式的核心给介绍完了,或许,您会觉得单例模式就这么个东西啊,不就是保证只有一个实例嘛,也太简单了,如果您真这么想的话,那您就错了,因为要保证在整个应用程序生命周期中保证只有一个实例不是那么容易的,下面就来看一种情况(这里先假设我的应用程序是多线程应用程序),同时还是以前面的Demo 来做为说明,如果在一开始调用GetInstance()时,是由两个线程同时调用的(这种情况是很常见的),注意是同时,(或者是一个线程进入if 判断语句后但还没有实例化Singleton 时,第二个线程到达,此时singleton 还是为null)这样的话,两个线程均会进入GetInstance(),而后由于是第一次调用GetInstance(),所以存储在Singleton 中的静态变量singleton 为null ,这样的话,就会让两个线程均通过if 语句的条件判断,然后调用new Singleton()了,public static Singleton GetInstance(){if (singleton == null){singleton = new Singleton();}return singleton;}这样的话,问题就出来了,因为有两个线程,所以会创建两个实例,很显然,这便违法了单例模式的初衷了,那么如何解决上面出现的这个问题(即多线程下使用单例模式时有可能会创建多个实例这一现象)呢?其实,这个是很好解决的,您可以这样思考这个问题:由于上面出现的问题中涉及到多个线程同时访问这个GetInstance(),那么您可以先将一个线程锁定,然后等这个线程完成以后,再让其他的线程访问GetInstance ()中的if 段语句,比如,有两个线程同时到达如果 singleton != null的话,那么上面提到的问题是不会存在的,因为已经存在这个实例了,这样的话,所有的线程都无法进入if 语句块,也就是所有的线程都无法调用语句new Singleton()了,这样还是可以保证应用程序生命周期中的实例只存在一个,但是如果此时的singleton == null的话,那么意味着这两个线程都是可以进入这个if 语句块的,那么就有可能出现上面出现的单例模式中有多个实例的问题,此时,我可以让一个线程先进入if 语句块,然后我在外面对这个if 语句块加锁,对第二个线程呢,由于if 语句进行了加锁处理,所以这个进程就无法进入if 语句块而处于阻塞状态,当进入了if 语句块的线程完成new Singleton()后,这个线程便会退出if 语句块,此时,第二个线程就从阻塞状态中恢复,即就可以访问if 语句块了,但是由于前面的那个线程已近创建了Singleton 的实例,所以singleton != null ,此时,第二个线程便无法通过if 语句的判断条件了,即无法进入if 语句块了,这样便保证了整个生命周期中只存在一个实例,也就是只有第一个线程创建了Singleton 实例,第二个线程则无法创建实例。
Java设计模式之《单例模式》及应用场景
Java设计模式之《单例模式》及应⽤场景所谓单例,指的就是单实例,有且仅有⼀个类实例,这个单例不应该由⼈来控制,⽽应该由代码来限制,强制单例。
单例有其独有的使⽤场景,⼀般是对于那些业务逻辑上限定不能多例只能单例的情况,例如:类似于计数器之类的存在,⼀般都需要使⽤⼀个实例来进⾏记录,若多例计数则会不准确。
其实单例就是那些很明显的使⽤场合,没有之前学习的那些模式所使⽤的复杂场景,只要你需要使⽤单例,那你就使⽤单例,简单易理解。
所以我认为有关单例模式的重点不在于场景,⽽在于如何使⽤。
1、常见的单例模式有两种创建⽅式:所谓饿懒汉式与饿汉式(1)懒汉式 何为懒?顾名思义,就是不做事,这⾥也是同义,懒汉式就是不在系统加载时就创建类的单例,⽽是在第⼀次使⽤实例的时候再创建。
详见下⽅代码⽰例:public class LHanDanli {//定义⼀个私有类变量来存放单例,私有的⽬的是指外部⽆法直接获取这个变量,⽽要使⽤提供的公共⽅法来获取private static LHanDanli dl = null;//定义私有构造器,表⽰只在类内部使⽤,亦指单例的实例只能在单例类内部创建private LHanDanli(){}//定义⼀个公共的公开的⽅法来返回该类的实例,由于是懒汉式,需要在第⼀次使⽤时⽣成实例,所以为了线程安全,使⽤synchronized关键字来确保只会⽣成单例public static synchronized LHanDanli getInstance(){if(dl == null){dl = new LHanDanli();}return dl;}}(2)饿汉式 ⼜何为饿?饿者,饥不择⾷;但凡有⾷,必急⾷之。
此处同义:在加载类的时候就会创建类的单例,并保存在类中。
详见下⽅代码⽰例:public class EHanDanli {//此处定义类变量实例并直接实例化,在类加载的时候就完成了实例化并保存在类中private static EHanDanli dl = new EHanDanli();//定义⽆参构造器,⽤于单例实例private EHanDanli(){}//定义公开⽅法,返回已创建的单例public static EHanDanli getInstance(){return dl;}}2、双重加锁机制 何为双重加锁机制? 在懒汉式实现单例模式的代码中,有使⽤synchronized关键字来同步获取实例,保证单例的唯⼀性,但是上⾯的代码在每⼀次执⾏时都要进⾏同步和判断,⽆疑会拖慢速度,使⽤双重加锁机制正好可以解决这个问题:public class SLHanDanli {private static volatile SLHanDanli dl = null;private SLHanDanli(){}public static SLHanDanli getInstance(){if(dl == null){synchronized (SLHanDanli.class) {if(dl == null){dl = new SLHanDanli();}}}return dl;}}看了上⾯的代码,有没有感觉很⽆语,双重加锁难道不是需要两个synchronized进⾏加锁的吗? ...... 其实不然,这⾥的双重指的的双重判断,⽽加锁单指那个synchronized,为什么要进⾏双重判断,其实很简单,第⼀重判断,如果单例已经存在,那么就不再需要进⾏同步操作,⽽是直接返回这个实例,如果没有创建,才会进⼊同步块,同步块的⽬的与之前相同,⽬的是为了防⽌有两个调⽤同时进⾏时,导致⽣成多个实例,有了同步块,每次只能有⼀个线程调⽤能访问同步块内容,当第⼀个抢到锁的调⽤获取了实例之后,这个实例就会被创建,之后的所有调⽤都不会进⼊同步块,直接在第⼀重判断就返回了单例。
JAVA常用设计模式详解大全
JAVA常用设计模式详解大全设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
它是将设计经验系统化的产物,目的是提高代码的可复用性、可维护性和可扩展性。
常用的设计模式主要分为三类:创建型模式、结构型模式和行为型模式。
下面将详细介绍每一种模式及其使用方式。
一、创建型模式1. 单例模式(Singleton Pattern)单例模式用于确保一个类只有一个实例,并提供全局访问方法。
常用于线程池、缓存和日志等场景。
2. 工厂模式(Factory Pattern)工厂模式用于根据不同的输入参数创建不同的实例。
常用于对象的创建过程复杂或者需要隐藏创建逻辑的场景。
3. 抽象工厂模式(Abstract Factory Pattern)抽象工厂模式用于创建一系列相关或依赖的对象,且客户端无需关心具体的实现类。
常用于创建多个产品族的场景。
4. 建造者模式(Builder Pattern)建造者模式用于将一个复杂对象的创建过程和其表示分离,以使同样的创建过程可以创建不同的表示。
常用于构建参数较多的对象。
5. 原型模式(Prototype Pattern)原型模式用于创建对象的克隆,避免了通过new关键字创建对象的性能开销。
常用于创建对象的过程耗费资源较多的场景。
二、结构型模式1. 适配器模式(Adapter Pattern)适配器模式用于将一个类的接口转换为客户端所期望的接口。
常用于不兼容接口之间的适配。
2. 装饰器模式(Decorator Pattern)装饰器模式用于动态地给一个对象添加额外的功能。
常用于对原有类的功能进行扩展或包装。
3. 代理模式(Proxy Pattern)代理模式用于控制对其他对象的访问。
常用于远程代理、虚拟代理、保护代理等场景。
4. 外观模式(Facade Pattern)外观模式用于提供一个简化的接口,隐藏一系列复杂的子系统。
常用于简化复杂系统的接口调用过程。
浅析Java单例设计模式(自写demo)
浅析Java单例设计模式(⾃写demo)⽬录单例模式特点单例模式优点实现⽅式饿汉式(线程安全)懒汉式单例模式特点1、构造器私有2、在⼀个Java应⽤程序中,可保证只有⼀个实例对象3、只提供⼀个供外界调⽤的getInstance()⽅法单例模式优点1、减少某些对象的频繁创建,降低系统开销和内存占⽤2、外部调⽤不使⽤new关键字,降低系统内存的使⽤频率3、对于特殊的类,在系统中只能存在⼀个实例,否则系统⽆法正常运⾏,⽐如Controller实现⽅式这⾥简单介绍两种实现⽅式饿汉式(线程安全)/*** @author: xuzhilei6656* @create: 2021-12-12 12:07* @description: 单例模式(饿汉式)**/public class Singleton {//创建实例private static Singleton instance = new Singleton();//私有构造器private Singleton(){}//获取实例的静态⽅法public static Singleton getInstance(){return instance;}}实例对象在类被加载的时候就已经完成初始化,外界调⽤拿到的都是这个唯⼀的实例对象懒汉式/*** @author: xuzhilei6656* @create: 2021-12-12 12:22* @description: 单例模式(懒汉式)**/public class Singleton {//声明⼀个变量private static Singleton instance;//私有构造器private Singleton(){}//获取实例的静态⽅法public static Singleton getInstance(){//如果是⾸次调⽤,实例对象还没有被创建,就需要创建,否则都是返回已经创建过的那个对象if (instance == null){instance = new Singleton();}return instance;}}对⽐饿汉式可见,实例对象在类被加载的时候并没有进⾏创建,在⾸次调⽤的时候才被创建,以后再被调⽤,返回的也是那个唯⼀的实例对象。
Java设计模式之(一)------单例模式
Java设计模式之(⼀)------单例模式1、什么是单例模式 采取⼀定的办法保证在整个软件系统中,确保对于某个类只能存在⼀个实例。
单例模式有如下三个特点: ①、单例类只能有⼀个实例 ②、单例类必须⾃⼰创建⾃⼰的实例 ③、单例类必须提供外界获取这个实例的⽅法2、单例类的设计思想(Singleton) ①、外界不能创建这个类的实例,那么必须将构造器私有化。
public class Singleton {//构造器私有化private Singleton(){}} ②、单例类必须⾃⼰创建⾃⼰的实例,不能允许在类的外部修改内部创建的实例。
⽐如将这个实例⽤ private 声明。
为了外界能访问到这个实例,我们还必须提供 get ⽅法得到这个实例。
因为外界不能 new 这个类,所以我们必须⽤ static 来修饰字段和⽅法。
//在类的内部⾃⼰创建实例private static Singleton singleton = new Singleton();//提供get ⽅法以供外界获取单例public Singleton getInstance(){ return singleton;} ③、是否⽀持延迟加载? 有些情况下,创建某个实例耗时长,占⽤资源多,⽤的时候也少,我们会考虑在⽤到的时候才会去创建,这就是延迟加载。
但有些情况,按照 fail-fast 的设计原则(有问题及早暴露),⽐如某个实例占⽤资源很多,如果延迟加载,会在程序运⾏⼀段时间后OOM,如果在程序启动的时候就创建这个实例,我们就可以⽴即去修复,不会导致程序运⾏之后的系统奔溃。
所以,是否⽀持延迟加载需要结合实际情况考虑。
④、保证线程安全 这个是⼀定要考虑的,如果你写的单例类存在线程安全问题,那就是伪单例了。
3、单例类的⼏种实现⽅式3.1 单例模式之饿汉模式public class Singleton {//构造器私有化private Singleton(){}//在类的内部⾃⼰创建实例private static Singleton singleton = new Singleton();//提供get ⽅法以供外界获取单例public static Singleton getInstance(){return singleton;}} 测试:public static void main(String[] args) {Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1.equals(s2)); //true} 这种模式在类加载的时候实例 singleton 就已经创建并初始化好了,所以是线程安全的。
Java中的单例模式详解(完整篇)
Java中的单例模式详解(完整篇)⽬录前⾔WHATWHY饿汉式实现⼀:静态实例参数与静态代码块实现⼆:静态内部类懒汉式错误⼀:单线程实现错误⼆:同步⽅法错误三:同步代码块之单次检查错误四:同步代码块之双重检查正确:双重检查+阻⽌重排序枚举场景总结前⾔个⼈认为单例模式是设计模式中最简单也是最常⽤的⼀种,是对有限资源合理利⽤的⼀种⽅式。
这个模式看似简单,但是其中蕴含了关于并发、类加载、序列化等⼀系列深层次的知识,如果理解不够深,就有可能在⾼并发时遇到难以预期的异常,或者会造成资源浪费。
所以本⽂会从将⽬前Java领域最常⽤的⼏种单例模式列出来,供⼤家参考。
WHAT维基百科给出了解释、实现的思路以及应该注意的地⽅:单例模式,也叫单⼦模式,是⼀种常⽤的软件设计模式,属于创建型模式的⼀种。
在应⽤这个模式时,单例对象的类必须保证只有⼀个实例存在。
实现单例模式的思路是:⼀个类能返回对象⼀个引⽤(永远是同⼀个)和⼀个获得该实例的⽅法(必须是静态⽅法,通常使⽤getInstance这个名称);当我们调⽤这个⽅法时,如果类持有的引⽤不为空就返回这个引⽤,如果类保持的引⽤为空就创建该类的实例并将实例的引⽤赋予该类保持的引⽤;同时我们还将该类的构造函数定义为私有⽅法,这样其他处的代码就⽆法通过调⽤该类的构造函数来实例化该类的对象,只有通过该类提供的静态⽅法来得到该类的唯⼀实例。
单例模式在多线程的应⽤场合下必须⼩⼼使⽤。
如果当唯⼀实例尚未创建时,有两个线程同时调⽤创建⽅法,那么它们同时没有检测到唯⼀实例的存在,从⽽同时各⾃创建了⼀个实例,这样就有两个实例被构造出来,从⽽违反了单例模式中实例唯⼀的原则。
解决这个问题的办法是为指⽰类是否已经实例化的变量提供⼀个互斥锁(虽然这样会降低效率)。
类图是:WHY正如定义所说,单例模式就是整个内存模型中,只有⼀个实例。
实例少了,内存占⽤就少。
同时,只有⼀个实例,也就只需要构建⼀个对象,计算就少。
深入理解java设计模式之单例模式
深⼊理解java设计模式之单例模式今天看了⼀天的设计模式。
单例模式:常⽤的分为两种懒汉模式和饿汉模式单例模式:1、单例类确保⾃⼰只有⼀个实例。
2、单例类必须⾃⼰创建⾃⼰的实例。
3、单例类必须为其他对象提供唯⼀的实例。
举个例⼦,⽹站的计数器就是单例模式的⼀个体现。
因为总不能打开⼀次⽹址就去new⼀个新的计数器对象。
⽽是⼤家都去⽤⼀个计数器下⾯来点⼲货数据库的连接池⼀般也是使⽤单例模式去实现的。
单例模式常⽤的分为两种懒汉模式://懒汉式单例类.在第⼀次调⽤的时候实例化⾃⼰public class Singleton {private Singleton() {}private static Singleton single=null;//静态⼯⼚⽅法public static Singleton getInstance() {if (single == null) {single = new Singleton();}return single;}}public class Singleton {private static class LazyHolder {private static final Singleton INSTANCE = new Singleton(); //使⽤静态内部类的⽅式实现线程安全,这个没研究。
}private Singleton (){}public static final Singleton getInstance() {return LazyHolder.INSTANCE;}}考虑到线程可能并发的可能,所以懒汉模式是线程不安全的。
然⽽我们可以去使⽤ synchronized 这个⽅法让所有的访问去同步,从⽽实现线程安全但是在⽹上看java有反射机制,通过Java反射机制是能够实例化构造⽅法为private的类的,这⾥姑且先不考虑反射机制。
但是我们的知道!饿汉模式://饿汉式单例类.在类初始化时,已经⾃⾏实例化public class Singleton1 {private Singleton1() {}private static final Singleton1 single = new Singleton1();//静态⼯⼚⽅法public static Singleton1 getInstance() {return single;}}饿汉式在类创建的同时就已经创建好⼀个静态的对象供系统使⽤,以后不再改变,所以天⽣是线程安全的。
java枚举单例模式解析
java枚举单例模式解析Java中的枚举单例模式是一种非常安全且简单的单例模式实现方式。
它利用枚举类型的特性,保证了在任何情况下都只会有一个实例被创建,并且可以避免反射和序列化等问题。
在枚举类型中,每个枚举常量都是枚举类型的实例。
因此,通过定义枚举常量来实现单例模式,可以保证只有一个实例对象被创建。
同时,枚举类型在加载时会被初始化,因此可以避免线程安全问题。
下面是一个使用枚举实现单例模式的例子:```javapublic enum Singleton {INSTANCE;public void showMessage() {System.out.println('Hello World!');}}```在上面的例子中,我们定义了一个枚举类型Singleton,其中只有一个枚举常量INSTANCE。
通过定义INSTANCE枚举常量来实现单例模式,可以保证只有一个实例对象被创建。
我们可以通过以下方式来调用Singleton实例对象的方法:```javaSingleton.INSTANCE.showMessage();```在使用枚举单例模式时,需要注意以下几点:1. 枚举类型不支持继承,因此无法通过继承来扩展单例的功能。
2. 枚举类型的构造函数只会被调用一次,在枚举常量被加载时进行初始化。
3. 枚举常量可以实现接口,在枚举类型中实现接口的方法可以被所有枚举常量共享。
总之,使用枚举单例模式可以保证线程安全和单例对象的唯一性,并且可以避免反射和序列化等问题。
因此,在需要实现单例模式时,可以考虑使用枚举单例模式。
java设计模式之单例模式
java设计模式之单例模式详解(设计模式)Design pattern主要经典的设计模式总共有二十三种,现在我们来看看设计模式中第一个经典设计模式单例模式(Singleton)。
单例模式表示一个类只会生成唯一的一个对象。
单例模式有两张实现方式:第一种:publicclass Singleton {publicstaticvoid main(String[] args) {A a1=A.getInstance();A a2=A.getInstance();System.out.println(a1==a2);//判断A类型的引用是否相等,是的话返回true,}}class A{privatestatic A a=new A();//必须用修饰符private,且static修饰,否则无法被静态方法使用private A(){ //构造方法也要设成私有的,这样防止在别的方法里new 一个A。
}publicstatic A getInstance(){ //获得实例,且用static是为了使用方便使用类调用静态方法,因为构造方法已经new,无法生成一个引用啊return a; //将返回A类型的引用 a的地址,即new A();}}第二种:publicclass Singleton {publicstaticvoid main(String[] args) {A a1=A.getInstance();A a2=A.getInstance();System.out.println(a1==a2);//判断A类型的引用是否相等,是的话返回true,}}class A{privatestatic A a;//必须用修饰符private,且static修饰,否则无法被静态方法使用private A(){ //构造方法也要设成私有的,这样在别的方法里就无法new 一个A。
}publicstatic A getInstance(){ //获得实例if(a==null){a=new A();}return a; //将返回A类型的引用 a的地址,即new A();}}总结:单例模式有以下特点:1、单例类只能有一个实例。
单例模式—四种写法详解
单例模式—四种写法详解单例定义:⼀个类只有⼀个实例,并提供⼀个全局访问点。
巧妙利⽤了编程语⾔的⼀些语法规则:构造函数private, 然后提供⼀个public的⽅法返回类的⼀个实例;⼜⽅法和返回的类的实例都是static 类型,所以只能被类所拥有,⽽不能被实例化类的对象拥有。
这样⼀个类就只能有⼀个实例了。
1. 最简单的写法(⾮线程安全,有叫它“懒汉式”的)public class Singleton {private static Singleton uniqueInstance;private Singleton() {}public static Singleton getInstatnce() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;}} 2. 加”synchronized“保证多线程下的线程安全(同步代码块,⾼频访问时,性能较差)public class Singleton {private static Singleton uniqueInstance;private Singleton() {}public static synchronized Singleton getInstatnce() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;}} 3. ”急切“或”饿汉“式(线程安全,因为JVM加载此类时⽴即创建此类的唯⼀实例)public class Singleton {private static Singleton uniqueInstance = new Singleton();private Singleton() {}public static Singleton getInstatnce() {return uniqueInstance;}}View Code 4. ”双重检查加锁“ (⾯试常问)public class Singleton {private volatile static Singleton uniqueInstance;private Singleton() {}public static Singleton getInstatnce() {if (uniqueInstance == null){synchronized (Singleton.class) {if (uniqueInstance == null) {uniqueInstance = new Singleton();}}}return uniqueInstance;}}View Code注:第⼀次检查,如果实例不存在,则进⼊同步块;进⼊同步块后再次检查,防⽌第⼆个线程在第⼀个线程执⾏第⼆次检查之前,已经创建了⼀个实例。
java 单例注解
java 单例注解在Java 中,实现单例模式的方式有很多种,而且在不同的应用场景下,选择不同的实现方式是有意义的。
在较新的Java 版本中,特别是在Spring 框架中,可以使用注解来简化单例的实现。
以下是两种常见的使用注解实现单例的方式:1. Spring 的`@Component` 和`@Scope` 注解:```javaimport org.springframework.context.annotation.Scope;import ponent;@Component@Scope("singleton")public class MySingleton {private MySingleton() {// 私有构造方法,防止外部实例化}// 单例的业务逻辑}```在这个例子中,`@Component` 注解将类标记为一个Spring 组件,而`@Scope("singleton")` 注解指定了这个组件的作用域为单例。
2. 使用`enum` 实现单例:```javapublic enum MySingleton {INSTANCE;// 单例的业务逻辑}```在这个例子中,通过使用`enum` 来创建单例,这是一种推荐的线程安全的实现方式。
`INSTANCE` 枚举常量代表了单例实例。
选择使用哪种方式取决于你的项目需求和框架使用情况。
在使用Spring 框架的情况下,通常推荐使用`@Component` 注解。
如果你不使用Spring,而且只关注单例模式的实现,那么`enum` 实现方式是一种简单且线程安全的选择。
JAVA模式设计之单例模式
它的子类 RegSingletonChild 需要父类的帮助才能实例化。下图所示是登记式单例类子类的一个例子。 图中的关系表明,此类是由父类将子类实例化的。
下面是子类的源代码。
代码清单 4:登记式单例类的子类
import java.util.HashMap; public class RegSingletonChild extends RegSingleton { public RegSingletonChild() {} /** * 静态工厂方法 */ static public RegSingletonChild getInstance() { return (RegSingletonChild) RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" ); } /** * 一个示意性的商业方法 */ public String about() { return "Hello, I am RegSingletonChild."; } }
java exchangeservice 单例
《深度剖析Java ExchangeService单例模式》一、引言在Java开发中,单例模式是一种非常重要的设计模式,它可以保证一个类在运行时只能有一个实例,并提供了全局访问点。
而在Java中,ExchangeService是一个非常常见且重要的类,它用于处理Exchange邮件服务。
本文将深入探讨Java ExchangeService单例模式的实现和应用。
二、ExchangeService简介ExchangeService是Microsoft提供的用于访问和管理Exchange邮件系统的Java API,它提供了丰富的功能和接口,可以方便地与Exchange服务器进行交互,包括发送、接收邮件、管理日历、联系人等。
在实际的应用开发中,我们通常会使用ExchangeService来实现与Exchange服务器的通信。
三、单例模式的意义在使用ExchangeService的过程中,我们常常需要保证整个应用程序中只有一个ExchangeService实例,这就需要用到单例模式。
单例模式的意义在于:1. 节省资源:通过保证只有一个实例存在,避免了多次创建对象造成的资源浪费。
2. 简化访问:在整个应用程序中都可以使用同一个实例,简化了对ExchangeService的访问。
3. 统一管理:方便对单例对象的状态进行管理和控制。
四、ExchangeService的单例实现在Java中,实现单例模式通常可以采用饿汉式、懒汉式等方式。
对于ExchangeService来说,可以采用以下方式实现单例:```javapublic class ExchangeServiceSingleton {private static ExchangeService instance;private ExchangeServiceSingleton() {// 私有化构造方法,避免外部实例化}public static ExchangeService getInstance() {if (instance == null) {// 线程安全的创建实例synchronized (ExchangeServiceSingleton.class) {if (instance == null) {instance = new ExchangeService();// 进行初始化设置}}}return instance;}}```通过上述代码可以看到,通过静态变量和静态方法的结合,可以实现对ExchangeService的单例实例的创建和访问。
Java设计模式之单例模式(Singleton)
Java设计模式之单例模式(Singleton)前⾔:在总结okHttp的时候,为了管理⽹络请求使⽤到了单例模式,晚上实在没啥状态了,静下⼼来学习总结⼀下使⽤频率最⾼的设计模式单例模式。
单例模式:单例模式确保某个类只有⼀个实例,⽽且⾃⾏实例化并向整个系统提供这个实例。
单例特点:单例类只能有⼀个实例。
单例类必须⾃⼰创建⾃⼰的唯⼀实例。
单例类必须给所有其他对象提供这⼀实例。
单例分类:1).懒汉单例(1)⾮线程安全实现public class Singleton {private Singleton(){}private static Singleton instance;public static Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}}(2)线程安全实现⽅式⼀⽅法加同步这种实现⽅式效率不⾼public class Singleton {private Singleton(){}private static Singleton instance;public static synchronized Singleton getInstance(){if(instance == null){instance = new Singleton();}return instance;}}(3.)线程安全实现⽅式⼆双重检查锁定public class Singleton{private static Singleton single; //声明静态的单例对象的变量private Singleton(){} //私有构造⽅法public static Singleton getSingle(){ //外部通过此⽅法可以获取对象if(single == null){synchronized (Singleton.class) { //保证了同⼀时间只能只能有⼀个对象访问此同步块if(single == null){single = new Singleton();}}}return single; //返回创建好的对象}}2.)饿汉式单例类饿汉式在类创建的同时就已经创建好⼀个静态的对象供系统使⽤,以后不再改变,所以天⽣是线程安全的。
单例模式详解
单例模式详解单例模式是一种常用的设计模式,它可以确保一个类只有一个实例,并且提供了全局访问点。
在很多场景下,我们需要确保某个对象只有唯一的实例,比如数据库连接池、线程池等。
1. 什么是单例模式?单例模式是一种创建型设计模式,它能够确保一个类只有一个实例,并且提供了全局访问点。
这意味着无论何时何地都可以通过该类来获取到同一个对象。
2. 单例模式的优缺点优点:(1)节省系统资源:由于单例模式只创建一个对象,在使用过程中不会频繁地创建和销毁对象,从而减少了系统资源的消耗。
(2)方便统一管理:由于所有对该类的访问都通过同一个接口进行调用,因此方便对其进行统一管理和维护。
(3)避免重复操作:由于每次获取到的都是同一个对象,在处理相同业务逻辑时不会出现重复操作导致数据错误或者异常情况发生。
缺点:(1)可能造成性能问题:如果某个应用程序中存在大量使用单例模式的代码,则可能会影响整体性能表现。
因为在并发环境下需要加锁来控制多线程同时访问共享资源所带来额外开销。
(2)难以扩展功能:如果要扩展某个已经实现为单例形态的类,则必须修改原代码,在没有完善测试工具支持下可能引入新问题甚至破坏原有功能结构等风险。
3. 单利模式应用场景当以下条件满足之后考虑采用单利设计:(1)需要频繁创建和销毁某些资源;(2)需要全局共享访问权限;4. 实现方式饿汉方式:public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}}懒汉方式:public class Singleton {private static volatile Singleton instance = null;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}5. 总结总之,单利设计就像其他任何技术选择那样也具备自身特定优劣势及适合范围限制。
2020重新出发,JAVA设计模式之一单例模式
2020重新出发,JAVA设计模式之⼀单例模式单例模式(单例设计模式)详解在有些系统中,为了节省内存资源、保证数据内容的⼀致性,对某些类要求只能创建⼀个实例,这就是所谓的单例模式。
单例模式的定义与特点单例(Singleton)模式的定义:指⼀个类只有⼀个实例,且该类能⾃⾏创建这个实例的⼀种模式。
例如,Windows 中只能打开⼀个任务管理器,这样可以避免因打开多个任务管理器窗⼝⽽造成内存资源的浪费,或出现各个窗⼝显⽰内容的不⼀致等错误。
在计算机系统中,还有 Windows 的回收站、操作系统中的⽂件系统、多线程中的线程池、显卡的驱动程序对象、打印机的后台处理服务、应⽤程序的⽇志对象、数据库的连接池、⽹站的计数器、Web 应⽤的配置对象、应⽤程序中的对话框、系统中的缓存等常常被设计成单例。
单例模式有 3 个特点:1. 单例类只有⼀个实例对象;2. 该单例对象必须由单例类⾃⾏创建;3. 单例类对外提供⼀个访问该单例的全局访问点;单例模式的结构与实现单例模式是设计模式中最简单的模式之⼀。
通常,普通类的构造函数是公有的,外部类可以通过“new 构造函数()”来⽣成多个实例。
但是,如果将类的构造函数设为私有的,外部类就⽆法调⽤该构造函数,也就⽆法⽣成多个实例。
这时该类⾃⾝必须定义⼀个静态私有实例,并向外提供⼀个静态的公有函数⽤于创建或获取该静态私有实例。
下⾯来分析其基本结构和实现⽅法。
单例模式的结构单例模式的主要⾓⾊如下。
单例类:包含⼀个实例且能⾃⾏创建这个实例的类。
访问类:使⽤单例的类。
其结构如图 1 所⽰。
图1 单例模式的结构图单例模式的实现Singleton 模式通常有两种实现形式:懒汉式和饿汉式。
第 1 种:懒汉式单例该模式的特点是类加载时没有⽣成单例,只有当第⼀次调⽤ getlnstance ⽅法时才去创建这个单例。
代码如下:public class LazySingleton{private static volatile LazySingleton instance=null; //保证 instance 在所有线程中同步private LazySingleton(){} //private 避免类在外部被实例化public static synchronized LazySingleton getInstance(){//getInstance ⽅法前加同步if(instance==null){instance=new LazySingleton();}return instance;}}注意:如果编写的是多线程程序,则不要删除上例代码中的关键字 volatile 和 synchronized,否则将存在线程⾮安全的问题。
JAVA设计模式之单例模式(网上搜集整理版)
JAVA设计模式之单例模式一、单例模式的介绍Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。
全局对象和Singleton模式有本质的区别,因为大量使用全局对象会使得程序质量降低,而且有些编程语言根本不支持全局变量。
最重要的是传统的全局对象并不能阻止一个类被实例化多次。
Effecttive Java第二版中最新单例模式从Java 1.5发行版本起,实现Singleton的方法只需编写一个包含单个元素的枚举类型:// Enum singleton - the preferred approach - page 18public enum Elvis {INSTANCE;public void leaveTheBuilding() {System.out.println("Whoa baby, I'm outta here!");}// This code would normally appear outside the class!public static void main(String[] args) {Elvis elvis = Elvis.INSTANCE;elvis.leaveTheBuilding();}}这种方法在功能上与公有域方法相近,但是它更加简洁,无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。
虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法单例类只能有一个实例单例类必须自己创建自己的唯一实例。
单例类必须给所有其他对象提供这一实例。
三、单例模式的应用每台计算机可以由若干个打印机,但只能有一个Printer Spooler,避免有两个作业同时输出到打印机。
一个具有自动编号主键的表可以有多个用户同时使用,但数据库中只能有一个地方分配下一个主键。
java枚举单例模式解析
java枚举单例模式解析
Java中的枚举类型被广泛应用于设计单例模式。
在传统单例模式中,我们需要手动实现getInstance()方法来保证只有一个实例被创建。
但是,通过枚举,我们可以简单地定义一个枚举类型,该类型只有一个实例,而且该实例是在枚举类被加载时创建的。
以下是一个使用枚举类型实现单例模式的例子:
public enum Singleton {
INSTANCE;
public void doSomething() {
//...
}
}
在这个例子中,Singleton是一个枚举类型,它只有一个枚举常量:INSTANCE。
这个常量是在Singleton类被加载时创建的,因此它是线程安全的。
我们可以通过Singleton.INSTANCE来访问单例实例,而不需要使用getInstance()方法。
此外,枚举类型还提供了其他优点,例如:
1. 防止反序列化创建新实例:通过实现Serializable接口,我们可以在网络传输或存储到磁盘时将对象序列化和反序列化。
但是,如果我们使用枚举类型实现单例模式,那么我们不需要担心反序列化会创建新实例,因为枚举类型的序列化和反序列化已经由Java提供
了支持。
2. 避免使用反射:传统的单例模式可以通过反射机制来创建新实例。
但是,如果我们使用枚举类型实现单例模式,那么我们不需要担心反射会破坏单例,因为枚举类型的构造函数是私有的。
综上所述,使用枚举类型实现单例模式可以更加简单,安全和优雅。
因此,在设计单例模式时,我们应该优先考虑使用枚举类型。
详解Java_Singleton(单例)模式的好处
Singleton模式看起来简单,使用方法也很方便,但是真正用好,是非常不容易,需要对Java 的类,线程,内存等概念有相当的了解。
本文介绍了Singleton模式的使用方法及好处。
Java Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
在很多操作中,比如建立目录数据库连接都需要这样的单线程操作。
还有, singleton能够被状态化; 这样,多个单态类在一起就可以作为一个状态仓库一样向外提供服务,比如,你要论坛中的帖子计数器,每次浏览一次需要计数,单态类能否保持住这个计数,并且能synchronize的安全自动加1,如果你要把这个数字永久保存到数据库,你可以在不修改单态接口的情况下方便的做到。
另外方面,Singleton也能够被无状态化。
提供工具性质的功能,Java Singleton模式就为我们提供了这样实现的可能。
使用Singleton的好处还在于可以节省内存,因为它限制了实例的个数,有利于Java垃圾回收(garbage collection)。
我们常常看到工厂模式中类装入器(class loader)中也用Singleton模式实现的,因为被装入的类实际也属于资源。
如何使用?一般,Java Singleton模式通常有几种形式:1. public class Singleton {2.3. private Singleton(){}4.5. //在自己内部定义自己一个实例,是不是很奇怪?6. //注意这是private 只供内部调用7.8. private static Singleton instance = new Singleton();9.10. //这里提供了一个供外部访问本class的静态方法,可以直接访问11. public static Singleton getInstance() {12. return instance;13. }14. }第二种形式:1. public class Singleton {2.3. private static Singleton instance = null;4.5. public static synchronized Singleton getInstance() {6.7. //这个方法比上面有所改进,不用每次都进行生成对象,只是第一次8. //使用时生成实例,提高了效率!9. if (instance==null)10. instance=new Singleton();11. return instance; }12.13. }使用Singleton.getInstance()可以访问单态类。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Singleton模式可以是很简单的,它的全部只需要一个类就可以完成(看看这章可怜的UML图)。
但是如果在“对象创建的次数以及何时被创建”这两点上较真起来,Singleton模式可以相当的复杂,比头五种模式加起来还复杂,譬如涉及到DCL双锁检测(double checked locking)的讨论、涉及到多个类加载器(ClassLoader)协同时、涉及到跨JVM(集群、远程EJB等)时、涉及到单例对象被销毁后重建等。
对于复杂的情况,本章中会涉及到其中一些[1]目的:希望对象只创建一个实例,并且提供一个全局的访问点。
场景:Kerrigan对于Zerg来说是个至关重要的灵魂人物,无数的Drone、Zergling、Hydralisk……可以被创造、被牺牲,但是Kerrigan得存在关系到Zerg在这局游戏中的生存,而且Kerrigan是不允许被多次创造的,必须有且只有一个虫族刀锋女王的实例存在,这不是游戏规则,但这是个政治问题。
分析:如前面一样,我们还是尝试使用代码来描述访问Kerrigan的过程,看看下面的UML图,简单得我都不怎么好意思放上来占版面。
图6.1 单例模式的UML图结构是简单的,只是我们还有一些小小的要求如下:1.最基本要求:每次从getInstance()都能返回一个且唯一的一个Kerrigan 对象。
2.稍微高一点的要求:Kerrigan很忙,很多人找,所以希望这个方法能适应多线程并发访问。
3.再提高一点的要求:Zerg是讲究公务员效率的社会,希望找Kerrigan的方法性能尽可能高。
4.最后一点要求是Kerrigan自己提出的:体谅到Kerrigan太累,希望多些睡觉时间,因此Kerrigan希望实现懒加载(Lazy Load),在需要的时候才被构造。
5.原本打算说还提要处理多ClassLoader、多JVM等情况,不过还是不要把情况考虑的太复杂了,暂且先放过作者吧(-_-#)。
我们第一次写的单例模式是下面这个样子的:Java代码1./**2. * 实现单例访问Kerrigan的第一次尝试3. */4.public class SingletonKerriganA {5.6. /**7. * 单例对象实例8. */9. private static SingletonKerriganA instance = null;10.11. public static SingletonKerriganA getInstance() {12. if (instance == null) { //line A13. instance = new SingletonKerriganA(); //line B14. }15. return instance;16. }17.}这个写法我们把四点需求从上往下检测,发现第二点的时候就出了问题,假设这样的场景:两个线程并发调用SingletonKerriganA.getInstance(),假设线程一先判断完instance是否为null,既代码中的line A进入到line B的位置。
刚刚判断完毕后,JVM将CPU资源切换给线程二,由于线程一还没执行line B,所以instance仍然是空的,因此线程二执行了new SignletonKerriganA()操作。
片刻之后,线程一被重新唤醒,它执行的仍然是new SignletonKerriganA()操作,好了,问题来了,两个Kerrigan谁是李逵谁是李鬼?紧接着,我们做单例模式的第二次尝试:Java代码1./**2. * 实现单例访问Kerrigan的第二次尝试3. */4.public class SingletonKerriganB {5.6. /**7. * 单例对象实例8. */9. private static SingletonKerriganB instance = null;10.11. public synchronized static SingletonKerriganB getInstance(){12. if (instance == null) {13. instance = new SingletonKerriganB();14. }15. return instance;16. }17.}比起第一段代码仅仅在方法中多了一个synchronized修饰符,现在可以保证不会出线程问题了。
但是这里有个很大(至少耗时比例上很大)的性能问题。
除了第一次调用时是执行了SingletonKerriganB的构造函数之外,以后的每一次调用都是直接返回instance对象。
返回对象这个操作耗时是很小的,绝大部分的耗时都用在synchronized修饰符的同步准备上,因此从性能上说很不划算。
那继续把代码改成下面的样子:Java代码1./**2. * 实现单例访问Kerrigan的第三次尝试3. */4.public class SingletonKerriganC {5.6. /**7. * 单例对象实例8. */9. private static SingletonKerriganC instance = null;10.11. public static SingletonKerriganC getInstance() {12. synchronized (SingletonKerriganC.class) {13. if (instance == null) {14. instance = new SingletonKerriganC();15. }16. }17. return instance;18. }19.}基本上,把synchronized移动到代码内部是没有什么意义的,每次调用getInstance()还是要进行同步。
同步本身没有问题,但是我们只希望在第一次创建Kerrigan实例的时候进行同步,因此我们有了下面的写法——双重锁定检查(DCL)。
Java代码1./**2. * 实现单例访问Kerrigan的第四次尝试3. */4.public class SingletonKerriganD {5.6. /**7. * 单例对象实例8. */9. private static SingletonKerriganD instance = null;10.11. public static SingletonKerriganD getInstance() {12. if (instance == null) {13. synchronized (SingletonKerriganD.class) {14. if (instance == null) {15. instance = new SingletonKerriganD();16. }17. }18. }19. return instance;20. }21.}看起来这样已经达到了我们的要求,除了第一次创建对象之外,其他的访问在第一个if中就返回了,因此不会走到同步块中。
已经完美了吗?我们来看看这个场景:假设线程一执行到instance = new SingletonKerriganD()这句,这里看起来是一句话,但实际上它并不是一个原子操作(原子操作的意思就是这条语句要么就被执行完,要么就没有被执行过,不能出现执行了一半这种情形)。
事实上高级语言里面非原子操作有很多,我们只要看看这句话被编译后在JVM执行的对应汇编代码就发现,这句话被编译成8条汇编指令,大致做了3件事情:1.给Kerrigan的实例分配内存。
2.初始化Kerrigan的构造器3.将instance对象指向分配的内存空间(注意到这步instance就非null 了)。
但是,由于Java编译器允许处理器乱序执行(out-of-order),以及JDK1.5之前JMM(Java Memory Medel)中Cache、寄存器到主内存回写顺序的规定,上面的第二点和第三点的顺序是无法保证的,也就是说,执行顺序可能是1-2-3也可能是1-3-2,如果是后者,并且在3执行完毕、2未执行之前,被切换到线程二上,这时候instance因为已经在线程一内执行过了第三点,instance已经是非空了,所以线程二直接拿走instance,然后使用,然后顺理成章地报错,而且这种难以跟踪难以重现的错误估计调试上一星期都未必能找得出来,真是一茶几的杯具啊。
DCL的写法来实现单例是很多技术书、教科书(包括基于JDK1.4以前版本的书籍)上推荐的写法,实际上是不完全正确的。
的确在一些语言(譬如C语言)上DCL是可行的,取决于是否能保证2、3步的顺序。
在JDK1.5之后,官方已经注意到这种问题,因此调整了JMM、具体化了volatile关键字,因此如果JDK 是1.5或之后的版本,只需要将instance的定义改成“private volatile static SingletonKerriganD instance = null;”就可以保证每次都去instance都从主内存读取,就可以使用DCL的写法来完成单例模式。
当然volatile或多或少也会影响到性能,最重要的是我们还要考虑JDK1.42以及之前的版本,所以本文中单例模式写法的改进还在继续。
代码倒越来越复杂了,现在先来个返璞归真,根据JLS(Java Language Specification)中的规定,一个类在一个ClassLoader中只会被初始化一次,这点是JVM本身保证的,那就把初始化实例的事情扔给JVM好了,代码被改成这样:Java代码1./**2. * 实现单例访问Kerrigan的第五次尝试3. */4.public class SingletonKerriganE {5.6. /**7. * 单例对象实例8. */9. private static SingletonKerriganE instance = new SingletonKerriganE();10.11. public static SingletonKerriganE getInstance() {12. return instance;13. }14.}好吧,如果这种写法是完美的话,那前面那么几大段话就是作者在消遣各位读者。
这种写法不会出现并发问题,但是它是饿汉式的,在ClassLoader加载类后Kerrigan的实例就会第一时间被创建,饿汉式的创建方式在一些场景中将无法使用:譬如Kerrigan实例的创建是依赖参数或者配置文件的,在getInstance()之前必须调用某个方法设置参数给它,那样这种单例写法就无法使用了。