java单例设计模式-饿汉式-懒汉式
什么是设计模式?常用的设计模式有哪些?

什么是设计模式?常⽤的设计模式有哪些?设计模式就是经过前⼈⽆数次的实践总结出的,设计过程中可以反复使⽤的、可以解决特定问题的设计⽅法。
单例(饱汉模式、饥汉模式)1、构造⽅法私有化,让出了⾃⼰类中能创建外其他地⽅都不能创建2、在⾃⼰的类中创建⼀个单实例(饱汉模式是⼀出来就创建创建单实例,⽽饥汉模式需要的时候才创建)3、提供⼀个⽅法获取该实例对象(创建时需要进⾏⽅法同步)⼯⼚模式:Spring IOC就是使⽤了⼯⼚模式.对象的创建交给⼀个⼯⼚去创建。
代理模式:Spring AOP就是使⽤的动态代理。
单例设计模式精讲定义:保证⼀个类只有⼀个实例,并且提供⼀个全局访问点场景:线程池,数据库连接池实现⽅式: 1.懒汉模式(只有使⽤的时候,再进⾏初始化,延迟加载) 2.饿汉模式 3.静态内部类 4.反射攻击 6.序列化 7.jdk源码1.懒汉模式实现的写法public class SingletonTest {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {LazySingleton lazySingleton = LazySingleton.getInstance();System.out.println(lazySingleton);}}).start();new Thread(new Runnable() {@Overridepublic void run() {LazySingleton lazySingleton = LazySingleton.getInstance();System.out.println(lazySingleton);}}).start();//两个线程打印出来的线程实例是同⼀个,说明是单例}}//使⽤的时候才开始实例化,JVM中⼀个实例class LazySingleton {private volatile static LazySingleton instance;public static LazySingleton getInstance() {if (instance == null) {synchronized (LazySingleton.class) {if (instance == null) {instance = new LazySingleton();}}}return instance;}private LazySingleton() {}}2.饿汉模式在类加载阶段完成了实例的初始化,通过类加载机制来保证线程的安全类的加载过程1加载=》加载对应的⼆进制⽂件,并且在⽅法区创建对应的数据结构连接:a.验证 b.准备 c.解析初始化:给静态属性赋值public class HungrySingletonTest {public static void main(String[] args) {HungrySingleton hungrySingleton = HungrySingleton.getInstance();}}class HungrySingleton {private static HungrySingleton instance = new HungrySingleton();public static HungrySingleton getInstance() {return instance;}private HungrySingleton() { }}3.基于静态内部类的单例public class AntiTest {public static void main(String[] args) throws NoSuchMethodException,IllegalAccessException, InvocationTargetException, InstantiationException{ InnerClassSingleton instance = InnerClassSingleton.getInstance();System.out.println(instance);//抛出异常,单例,不允许有多个实例Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor();declaredConstructor.setAccessible(true);InnerClassSingleton innerClassSingleton = declaredConstructor.newInstance();System.out.println(innerClassSingleton);}}class InnerClassSingleton{static class InnerClass{private static InnerClassSingleton instance = new InnerClassSingleton();}public static InnerClassSingleton getInstance(){return InnerClass.instance;}private InnerClassSingleton(){if ((InnerClass.instance!=null)){throw new RuntimeException("单例类,不允许多个实例!");}}}4.枚举单例public class EnumSingletonTest{public static void main(String[] args) {EnumSingleton instance = EnumSingleton.INSTANCE;EnumSingleton instance1 = EnumSingleton.INSTANCE;System.out.println(instance==instance1);//trueinstance.print();// 149928006instance1.print();// 149928006}}enum EnumSingleton {INSTANCE;public void print(){System.out.println(this.hashCode());}}。
java 单例写法

java 单例写法在Java编程中,单例模式是一种设计模式,意味着仅仅存在一个实例对象。
单例模式是一种常见的面向对象编程技巧,在很多情况下,它可以有效地提高程序的性能并且降低系统的复杂度。
下面我们来学习一下Java单例写法,并进行阐述。
第一步:通过私有构造函数来防止其他类实例化单例类在Java中,我们需要通过私有构造函数来防止外部类的实例化。
这里我们提供一个例子,代码如下:public class Singleton {private static Singleton instance;private Singleton() { }public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}在上述代码中,我们通过私有构造函数来防止其他类实例化Singleton类。
由于我们只需要一个实例,因此我们对实例对象进行了私有化。
这样,我们便可以使用getInstance()函数来获取类的实例,从而确保该类只存在一个实例。
第二步:实现懒汉式单例懒汉式单例模式是指在需要时创建实例。
在该模式种,单例类的实例不会在程序启动时就创建,而是在调用getInstance()方法时创建。
代码如下:public class LazySingleton {private static volatile LazySingleton instance =null;private LazySingleton() { }public static LazySingleton getInstance() {if (instance == null) {synchronized (LazySingleton.class) {if (instance == null) {instance = new LazySingleton();}}}return instance;}}在上述代码中,getInstance()函数通过检查instance是否为空来实现懒汉式单例模式。
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业务代码而言,设计模式更是必不可少的工具。
本文将介绍Java业务代码中常用的设计模式,帮助读者更好地理解并应用设计模式。
二、单例模式单例模式是一种创建型模式,它保证一个类只有一个实例,并提供一个全局的访问点。
在Java业务代码中,单例模式经常用来表示全局的配置信息或共享的资源。
1. 懒汉式单例懒汉式单例模式在第一次调用时才会创建实例,使用时需要注意多线程并发访问时的线程安全性。
2. 饿汉式单例饿汉式单例模式在类加载时就创建实例,不存在线程安全问题,但可能会造成资源浪费。
3. 双重检查锁单例双重检查锁单例模式结合了懒汉式和饿汉式的优点,通过双重判断和加锁实现线程安全的延迟加载。
三、工厂模式工厂模式是一种创建型模式,它定义了一个创建对象的接口,但让子类决定实例化哪个类。
在Java业务代码中,工厂模式可以根据参数或配置来创建不同的对象实例。
1. 简单工厂模式简单工厂模式通过一个工厂类根据传入的参数来创建对象实例,但违反了开闭原则,因为每次新增类型都需要修改工厂类。
2. 工厂方法模式工厂方法模式定义了一个创建对象的接口,由子类决定实例化哪个类,符合开闭原则。
3. 抽象工厂模式抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,适用于创建一整套产品。
四、代理模式代理模式是一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。
在Java业务代码中,代理模式可以用来控制对对象的访问,实现横切关注点的处理。
1. 静态代理静态代理通过手动编写代理类来实现对目标对象的访问控制,但需要为每个接口手动编写代理类,增加了代码量。
2. 动态代理动态代理利用Java的动态代理机制,在运行时动态生成代理类,减少了重复代码,但需要目标对象实现接口。
3. CGLIB代理CGLIB代理通过继承目标对象的方式动态创建代理类,不要求目标对象实现接口,但无法代理final方法和类。
java自己小整理

自个儿的整理:1. hibernate的好处:第一:数据库连接不需要我们自己来管理,如打开和关闭(优点吧)第二:Hibernate对原来的SQL语句进行了封装,以前写很多SQL语句,现在你在保存的时候直接可以用SA VE(对象)来实现了。
(节省代码吧)第三:原来是对表操作,现在是对对象操作,想法上是不是更好呢?都是对象。
Java单例模式java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。
单例模式有一下特点:1、单例类只能有一个实例。
2、单例类必须自己自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。
这些应用都或多或少具有资源管理器的功能。
每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。
每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。
总之,选择单例模式就是为了避免不一致状态,避免政出多头。
首先看一个经典的单例实现。
public class Singleton {private static Singleton uniqueInstance = null;private Singleton() {// Exists only to defeat instantiation.}public static Singleton getInstance() {if (uniqueInstance == null) {uniqueInstance = new Singleton();}return uniqueInstance;}// Other methods...}Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。
什么是Singleton?

什么是Singleton?Singleton:在Java中即指单例设计模式,它是软件开发中最常⽤的设计模式之⼀。
单:指唯⼀例:指实例单例设计模式,即某个类在整个系统中只能有⼀个实例对象可被获取和使⽤的代码模式。
要点:⼀、单例类只能有⼀个实例保证构造器私有化(防⽌通过构造器实例化)⼆、单例类必须⾃信创建这个实例在单例类中创建⼀个静态变量来保存这个唯⼀的实例三、单例类必须⾃⾏向整个系统提供这个实例对外提供该实例对象的获取⽅式1. 直接暴露该实例对象2. ⽤静态变量的get⽅法获取该实例对象单例的⼏种常见形式饿汉式:直接创建对象,不存在线程安全问题直接实例化饿汉式(简介直观)1/**2 * 单例饿汉式⼀(1)3 * 直接实例化饿汉式(简洁直观)4 * 对外提供获取该实例对象的⽅式:5 * (1)直接暴露6 * (2)⽤静态变量的get⽅法获取7*/8public class SingletonHungry1 {910public static final SingletonHungry1 INSTANCE = new SingletonHungry1();1112private SingletonHungry1() {}13 }141516/**17 * 单例饿汉式⼀(2)18 * 直接实例化饿汉式(简洁直观)19 * 对外提供获取该实例对象的⽅式:20 * (1)直接暴露21 * (2)⽤静态变量的get⽅法获取22*/23public class SingletonHungry2 {2425private static final SingletonHungry2 INSTANCE = new SingletonHungry2();2627private SingletonHungry2() {}2829public static SingletonHungry2 getInstance() {30return INSTANCE;31 }32 }枚举式(最简洁)1/**2 * 单例饿汉式⼆3 * 枚举式(最简洁)4*/5public enum SingletonHungry3 {6 INSTANCE7 }静态代码块饿汉式(适合复杂实例化)2 * 单例饿汉式三3 * 静态代码块饿汉式(适合复杂实例化)4*/5public class SingletonHungry4 {67public static final SingletonHungry4 INSTANCE;89private String info;1011static {12// 这⾥⽤来实现复杂的实例化13// ......复杂代码14try {15 Properties pro = new Properties();16 pro.load(SingletonHungry4.class.getClassLoader().getResourceAsStream("singleton.properties"));17 INSTANCE = new SingletonHungry4(pro.getProperty("info"));18 } catch (IOException e) {19throw new RuntimeException(e);20 }21 }2223private SingletonHungry4(String info) { = info;25 }26 }懒汉式:延迟创建对象线程不安全(适⽤于单线程)1/**2 * 单例懒汉式⼀3 * 线程不安全(适⽤于单线程)4*/5public class SingletonLazy1 {67private static SingletonLazy1 INSTANCE;89private SingletonLazy1() {}1011public static SingletonLazy1 getInstance() {12if (INSTANCE == null) {13try {14 Thread.sleep(100);15 } catch (InterruptedException e) {16 e.printStackTrace();17 }18 INSTANCE = new SingletonLazy1();19 }20return INSTANCE;21 }22 }线程安全(适⽤于多线程)1/**2 * 单例懒汉式⼆(1)3 * 线程安全(适⽤于多线程)4*/5public class SingletonLazy2 {67private static SingletonLazy2 INSTANCE;89private SingletonLazy2() {}1011public static SingletonLazy2 getInstance() {12synchronized (SingletonLazy2.class) {13if (INSTANCE == null) {14try {15 Thread.sleep(100);16 } catch (InterruptedException e) {17 e.printStackTrace();18 }19 INSTANCE = new SingletonLazy2();20 }21 }22return INSTANCE;23 }24 }2527 * 单例懒汉式⼆(2)28 * 线程安全(适⽤于多线程,优化效率)29*/30public class SingletonLazy3 {3132private static SingletonLazy3 INSTANCE;3334private SingletonLazy3() {}3536public static SingletonLazy3 getInstance() {37if (INSTANCE == null) { // 不等于空直接返回,提⾼效率38synchronized (SingletonLazy3.class) {39if (INSTANCE == null) {40try {41 Thread.sleep(100);42 } catch (InterruptedException e) {43 e.printStackTrace();44 }45 INSTANCE = new SingletonLazy3();46 }47 }48 }4950return INSTANCE;51 }52 }静态内部类形式(适⽤于多线程) 在内部类被加载和初始化时,才创建INSTANCE实例对象 静态内部类不会⾃动随着外部类的加载和初始化⽽初始化,它是要单独去加载和初始化的 因为是在内部类加载和初始化时创建的,因此是线程安全的1/**2 * 单例懒汉式三3 * 静态内部类(适⽤于多线程)4 * 在内部类被加载和初始化时,才创建INSTANCE实例对象5 * 静态内部类不会⾃动随着外部类的加载和初始化⽽初始化,它是要单独去加载和初始化的6 * 因为是在内部类加载和初始化时,创建的,因此是线程安全的7*/8public class SingletonLazy4 {910private SingletonLazy4() {}1112private static class Inner {13private static final SingletonLazy4 INSTANCE = new SingletonLazy4();14 }1516public static SingletonLazy4 getInstance() {17return Inner.INSTANCE;18 }19 }本⽂⽤于记录Singleton的学习,⽅便以后回顾!学完的东西容易忘,以⽂章的形式记录下来。
java设计模式面试题

java设计模式面试题Java 设计模式面试题设计模式是软件开发中常用的解决问题的方法论,它通过提供经过验证的解决方案来应对各种软件设计问题。
在面试中,设计模式也是经常被问到的内容之一。
本文将介绍一些常见的Java 设计模式面试题,并给出对应的解答。
一、单例模式(Singleton Pattern)单例模式是一种创建型设计模式,其目的是保证一个类只有一个实例,并提供一个全局访问点。
常见的实现方式有懒汉式和饿汉式。
1. 懒汉式实现单例模式的代码示例:```javapublic class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}2. 饿汉式实现单例模式的代码示例:```javapublic class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}}```二、工厂模式(Factory Pattern)工厂模式是一种创建型设计模式,其通过提供一个公共接口来创建对象,而不需要暴露对象的创建逻辑。
1. 简单工厂模式的代码示例:```javapublic interface Shape {void draw();public class Circle implements Shape {@Overridepublic void draw() {System.out.println("Draw a circle.");}}public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Draw a rectangle.");}}public class ShapeFactory {public Shape createShape(String shapeType) {if (shapeType.equalsIgnoreCase("circle")) {return new Circle();} else if (shapeType.equalsIgnoreCase("rectangle")) { return new Rectangle();}return null;}}```2. 抽象工厂模式的代码示例:```javapublic interface Shape {void draw();}public interface Color {void fill();}public class Circle implements Shape { @Overridepublic void draw() {System.out.println("Draw a circle."); }}public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("Draw a rectangle."); }}public class Red implements Color {@Overridepublic void fill() {System.out.println("Fill with red color."); }}public class Blue implements Color {@Overridepublic void fill() {System.out.println("Fill with blue color."); }}public abstract class AbstractFactory {public abstract Shape createShape(String shapeType); public abstract Color createColor(String colorType);}public class ShapeFactory extends AbstractFactory {@Overridepublic Shape createShape(String shapeType) {if (shapeType.equalsIgnoreCase("circle")) {return new Circle();} else if (shapeType.equalsIgnoreCase("rectangle")) { return new Rectangle();}return null;}@Overridepublic Color createColor(String colorType) {return null;}}public class ColorFactory extends AbstractFactory {@Overridepublic Shape createShape(String shapeType) {return null;}@Overridepublic Color createColor(String colorType) {if (colorType.equalsIgnoreCase("red")) {return new Red();} else if (colorType.equalsIgnoreCase("blue")) {return new Blue();}return null;}}```三、观察者模式(Observer Pattern)观察者模式是一种行为型设计模式,其定义了对象之间的一对多依赖关系,使得当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
单例的七种写法

单例的七种写法单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供一个全局访问点。
在实际开发中,我们经常会遇到需要使用单例模式的场景。
在Java中,单例模式有七种写法,下面我们来逐一介绍。
1. 饿汉式单例模式饿汉式单例模式指的是在类加载时就实例化了该类的唯一实例。
这种写法没有使用锁,因此线程安全。
代码如下:```public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}}```2. 懒汉式单例模式懒汉式单例模式指的是在第一次使用时才实例化该类的唯一实例。
这种写法需要使用同步锁,因此效率较低。
代码如下:```public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}```3. 双重校验锁单例模式双重校验锁单例模式指的是先判断实例是否存在,若不存在,则进入同步块进行实例化,提高效率。
这种写法需要使用volatile修饰实例,保证线程安全。
代码如下:public 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;}}```4. 静态内部类单例模式静态内部类单例模式指的是利用静态内部类的加载机制实现单例。
饿汉式和懒汉式的区别

饿汉式和懒汉式的区别单例模式中的懒汉模式和饿汉模式是什么?区别又是什么?1.懒汉模式:顾名思义,他是一个懒汉,他不愿意动弹。
什么时候需要吃饭了,他就什么时候开始想办法搞点食物。
即懒汉式一开始不会实例化,什么时候用就什么时候new,才进行实例化。
2.饿汉模式:顾名思义,他是一个饿汉,他很勤快就怕自己饿着。
他总是先把食物准备好,什么时候需要吃了,他随时拿来吃,不需要临时去搞食物。
即饿汉式在一开始类加载的时候就已经实例化,并且创建单例对象,以后只管用即可。
3.懒汉式代码实现:4.饿汉式代码实现:5.懒汉式和饿汉式的安全和性能区别:(1)线程安全:饿汉式在线程还没出现之前就已经实例化了,所以饿汉式一定是线程安全的。
懒汉式加载是在使用时才会去new 实例的,那么你去new的时候是一个动态的过程,是放到方法中实现的,比如:如果这个时候有多个线程访问这个实例,这个时候实例还不存在,还在new,就会进入到方法中,有多少线程就会new出多少个实例。
一个方法只能return一个实例,那最终return出哪个呢?是不是会覆盖很多new的实例?这种情况当然也可以解决,那就是加同步锁,避免这种情况发生。
(2)执行效率:饿汉式没有加任何的锁,因此执行效率比较高。
懒汉式一般使用都会加同步锁,效率比饿汉式差。
(3)内存使用:饿汉式在一开始类加载的时候就实例化,无论使用与否,都会实例化,所以会占据空间,浪费内存。
懒汉式什么时候用就什么时候实例化,不浪费内存。
单例模式——懒汉式和饿汉式详解单例模式作用:属于创建型模式的一种,应用于保证一个类仅有一个实例的场景下,并且提供了一个访问它的全局访问点,如spring中的全局访问点BeanFactory,spring下所有的bean都是单例。
特点:从系统启动到终止,整个过程只会产生一个实例。
常用写法:懒汉式,饿汉式,注册式,序列化式。
下面比较一下懒汉式和饿汉式:•懒汉式:默认不会实例化,什么时候用什么时候new。
Spring中常见的设计模式——单例模式

Spring中常见的设计模式——单例模式⼀、单例模式的应⽤场景 单例模式(singleton Pattern)是指确保⼀个类在任何情况下都绝对只有⼀个实例,并提供⼀个全局访问点。
J2EE中的ServletContext,ServletContextConfig等;Spring中的ApplicationContext、数据库连接池等。
⼆、饿汉式单例模式 饿汉式单例模式在类加载的时候就⽴即初始化,并且创建单例对象。
它是绝对的线程安全、在线程还没出现以前就实现了,不可能存在访问安全问题。
优点:没有增加任何锁,执⾏效率⾼,⽤户体验⽐懒汉式好。
缺点:类加载的时候就初始化了,⽤不⽤都进⾏,浪费内存。
Spring 中IoC容器ApplocationContext本⾝就是典型的饿汉式单例模式:public class HungrySingleton {private static final HungrySingleton h = new HungrySingleton();private HungrySingleton() {}public static HungrySingleton getInstance() {return h;}} 饿汉式单例模式适⽤于单例对象较少的情况。
三、懒汉式单例模式 被外部调⽤才会加载:public class LazySimpleSingleton {private LazySimpleSingleton() {}private static LazySimpleSingleton lazy = null;public static LazySimpleSingleton getInstance() {if (lazy == null) {lazy = new LazySimpleSingleton();}return lazy;}}利⽤线程创建实例:public class ExectorThread implements Runnable {@Overridepublic void run() {LazySimpleSingleton simpleSingleton = LazySimpleSingleton.getInstance();System.out.println(Thread.currentThread().getName() + ":" + simpleSingleton);}}客户端代码:public class LazySimpleSingletonTest {public static void main(String[] args) {Thread t1 = new Thread(new ExectorThread());Thread t2 = new Thread(new ExectorThread());t1.start();t2.start();System.out.println("END");}}结果:ENDThread-1:zySimpleSingleton@298c37fdThread-0:zySimpleSingleton@6ebc1cfd可以看到产⽣的两个实例的内存地址不同说明产⽣了两个实例,⼤家可以通过以下打断点的⽅式实现不同Thread运⾏状态见进⾏切换。
编程必备的23种设计模式

编程必备的23种设计模式转:建议⼤家学习编程的时候务必看看,看看底层如何实现,⽆论学习任何⼀门语⾔,我相信设计模式是必须掌握熟知的,此篇⽂章以语⾔为代表,讲解了23种设计模式,并有例⼦。
祝⼤家学习进步,QQ交流群127591054.设计模式建议书籍:Head First设计模式(Design pattern)是⼀套被反复使⽤、多数⼈知晓的、经过分类编⽬的、代码设计经验的总结。
使⽤设计模式是为了可重⽤代码、让代码更容易被他⼈理解、保证代码可靠性。
毫⽆疑问,设计模式于⼰于他⼈于系统都是多赢的,设计模式使代码编制真正⼯程化,设计模式是软件⼯程的基⽯,如同⼤厦的⼀块块砖⽯⼀样。
项⽬中合理的运⽤设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每⼀个模式描述了⼀个在我们周围不断重复发⽣的问题,以及该问题的核⼼解决⽅案,这也是它能被⼴泛应⽤的原因。
⼀、设计模式的分类创建型模式,共五种:⼯⼚⽅法模式、抽象⼯⼚模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
⾏为型模式,共⼗⼀种:策略模式、模板⽅法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
⼆、Java的23中设计模式1、⼯⼚⽅法模式(Factory Method)⼯⼚⽅法模式分为三种:普通⼯⼚模式多个⼯⼚⽅法模式静态⼯⼚⽅法模式1.1、普通⼯⼚模式,就是建⽴⼀个⼯⼚类,对实现了同⼀接⼝的产品类进⾏实例的创建例⼦://发送短信和邮件的接⼝public interface Sender {public void Send();}//发送邮件的实现类public class MailSender implements Sender {public void Send() {System.out.println("发送邮件!");}}//发送短信的实现类public class SmsSender implements Sender {public void Send() {System.out.println("发送短信!");}}//创建⼯⼚类public class SendFactory {//⼯⼚⽅法public Sender produce(String type) {if ("mail".equals(type)) {return new MailSender();} else if ("sms".equals(type)) {return new SmsSender();} else {System.out.println("请输⼊正确的类型!");return null;}}}//测试类public class FactoryTest {public static void main(String[] args) {SendFactory factory = new SendFactory();Sender sender = factory.produce("sms");sender.Send();}}1.2、多个⼯⼚⽅法模式是对普通⼯⼚⽅法模式的改进,在普通⼯⼚⽅法模式中,如果传递的字符串出错,则不能正确创建对象,⽽多个⼯⼚⽅法模式是提供多个⼯⼚⽅法,分别创建对象。
Java 设计模式练习题及答案

Java 设计模式练习题及答案在学习Java设计模式时,练习题是非常重要的一部分。
通过练习题的实践,可以更好地理解和应用设计模式,提升自己的编程能力。
本文将介绍一些Java设计模式练习题,并提供相应的答案,希望能对读者在设计模式的学习和实践中有所帮助。
一、题目一:单例模式——懒汉式实现问题描述:请编写一个线程安全的懒汉式单例模式。
解答示例:```javapublic class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}}```二、题目二:工厂模式——简单工厂实现问题描述:请使用简单工厂模式实现一个计算器,支持加减乘除四种运算。
解答示例:```javapublic class CalculatorFactory {public static Calculator createCalculator(String operator) {Calculator calculator = null;switch (operator) {case "+":calculator = new AddCalculator();break;case "-":calculator = new SubtractCalculator();break;case "*":calculator = new MultiplyCalculator();break;case "/":calculator = new DivideCalculator();break;}return calculator;}}public interface Calculator {double calculate(double num1, double num2);}public class AddCalculator implements Calculator {@Overridepublic double calculate(double num1, double num2) { return num1 + num2;}}public class SubtractCalculator implements Calculator { @Overridepublic double calculate(double num1, double num2) {return num1 - num2;}}// MultiplyCalculator和DivideCalculator类似,省略代码// 使用示例Calculator calculator = CalculatorFactory.createCalculator("+");double result = calculator.calculate(2, 3); // 结果为5```三、题目三:观察者模式问题描述:请设计一个简单的气象站系统,该系统需要实现以下功能:1. 可以添加观察者并实时更新气象数据;2. 当气象数据发生变化时,自动通知所有观察者进行更新。
java设计模式期末考试和答案

java设计模式期末考试和答案## Java设计模式期末考试和答案### 一、选择题(每题2分,共10分)1. 以下哪个不是设计模式的分类?A. 创建型模式B. 结构型模式C. 行为型模式D. 功能型模式**答案:D**2. 单例模式属于哪种类型的设计模式?A. 创建型模式B. 结构型模式C. 行为型模式D. 功能型模式**答案:A**3. 以下哪个设计模式不是创建型模式?A. 工厂方法模式B. 抽象工厂模式C. 建造者模式D. 观察者模式**答案:D**4. 策略模式属于哪种类型的设计模式?A. 创建型模式B. 结构型模式C. 行为型模式D. 功能型模式**答案:C**5. 以下哪个不是结构型模式?A. 适配器模式B. 装饰器模式C. 代理模式D. 命令模式**答案:D**### 二、填空题(每题2分,共10分)1. 工厂方法模式中,工厂方法是一个______方法,用于创建______对象。
**答案:接口;具体产品**2. 建造者模式中,Director类负责______产品的构建过程,Builder类定义______产品对象的内部表示。
**答案:指导;创建**3. 代理模式中,Subject接口定义了______和______两个角色需要实现的方法。
**答案:RealSubject;Proxy**4. 观察者模式中,当______对象状态发生改变时,会通知所有______对象。
**答案:Subject;Observer**5. 策略模式中,Context类持有一个______对象的引用,用于执行算法。
**答案:Strategy**### 三、简答题(每题10分,共30分)1. 请简述单例模式的实现方式,并说明其优缺点。
**答案:**单例模式的实现方式通常有两种:懒汉式和饿汉式。
懒汉式在第一次调用时创建实例,而饿汉式在类加载时就创建实例。
优点是保证了全局只有一个实例,并提供一个全局访问点。
缺点是如果实例化对象需要很多资源,那么在不需要时也会占用这些资源。
arkts单例写法

arkts单例写法在Java 中,单例设计模式的目的是确保一个类只有一个实例,并提供一个全局访问点。
有多种方式实现单例模式,以下是其中一种在ArkTS(可能是指某个具体框架或库)中的实现方式,假设你的类名是`MySingleton`:1. 饿汉式单例模式(线程安全):```javapublic class MySingleton {// 在类加载时就创建实例private static final MySingleton instance = new MySingleton();// 私有构造方法,避免外部实例化private MySingleton() {}// 提供获取实例的方法public static MySingleton getInstance() {return instance;}// 其他方法...}```2. 懒汉式单例模式(线程安全,使用双重检查锁定):```javapublic class MySingleton {// 使用volatile 关键字确保可见性private static volatile MySingleton instance;// 私有构造方法,避免外部实例化private MySingleton() {}// 双重检查锁定public static MySingleton getInstance() {if (instance == null) {synchronized (MySingleton.class) {if (instance == null) {instance = new MySingleton();}}}return instance;}// 其他方法...}```在上述代码中,我们通过`getInstance` 方法获取`MySingleton` 类的唯一实例。
在实际使用中,选择饿汉式还是懒汉式取决于你的需求。
如果希望在类加载时就创建实例,可以选择饿汉式;如果希望在需要时再创建实例,可以选择懒汉式。
软件开发中常见的设计模式介绍

软件开发中常见的设计模式介绍在软件开发过程中,设计模式是一种被广泛应用的解决问题的方法。
设计模式可以提供在特定情境中重复使用的可行解决方案,有助于提高代码的可读性、可维护性和重用性。
本文将介绍几种常见的设计模式,包括工厂模式、观察者模式、单例模式和策略模式。
一、工厂模式工厂模式是一种常见的创建型设计模式,用于将对象的实例化过程封装起来。
它通过定义一个共同的接口来创建对象实例,使得客户端调用代码与具体的实现逻辑解耦。
工厂模式可以分为简单工厂模式、工厂方法模式和抽象工厂模式。
简单工厂模式通过一个工厂类来根据传入的参数决定创建哪个具体对象。
它的优点是实现简单,适用于对象类型较少且变化频率低的场景。
但是,当需要添加新的对象类型时,需要修改工厂类的代码,不符合开闭原则。
工厂方法模式通过定义一个抽象的工厂接口,由子类具体实现工厂方法来创建对象。
这种方式实现了对象的创建和使用的解耦,也符合开闭原则。
同时,工厂方法模式也可以在运行时动态地切换具体的子类工厂。
抽象工厂模式通过定义一个抽象的工厂接口,可以创建一组相关的对象。
它可以创建多个产品族的对象,且具有良好的扩展性。
但是,抽象工厂模式也增加了系统的复杂度和理解难度。
二、观察者模式观察者模式是一种常见的行为型设计模式,用于定义对象之间的一对多的依赖关系,使得当一个对象的状态发生变化时,其所依赖的对象都会得到通知并自动更新。
观察者模式分为被观察者和观察者两个角色。
被观察者维护一个观察者列表,并提供注册、移除和通知观察者的方法。
当被观察者的状态发生改变时,会遍历观察者列表,调用每个观察者的更新方法。
观察者接收到通知后,可以进行相应的处理。
观察者模式能够实现对象之间的松耦合,使得被观察者和观察者之间的依赖关系可以动态地建立和解除。
它也符合开闭原则,因为可以在运行时增加新的观察者。
三、单例模式单例模式是一种创建型设计模式,用于限制一个类只能创建一个实例。
它保证在整个应用程序中,只有一个实例存在,并提供了一个全局访问点。
软件开发中常见的设计模式

软件开发中常见的设计模式软件开发中,设计模式是一个非常重要的概念。
设计模式代表了一组被反复使用的最佳实践,可以用于解决特定问题。
设计模式可以帮助开发者更好地组织和管理代码,避免重复劳动,提高代码的可读性、可维护性和可扩展性。
下面,我们来介绍一些常见的设计模式。
一、单例模式单例模式是一种创建型模式,它保证一个类只有一个实例,并提供一个全局访问点。
单例模式通常用于管理资源,例如数据库连接、线程池、日志记录器等。
单例模式有几种实现方式,最常见的是饿汉式和懒汉式。
饿汉式在类加载时就会创建实例,而懒汉式则是在第一次使用时才会创建实例。
二、工厂模式工厂模式是一种创建型模式,它用工厂方法代替了new操作符来实例化对象。
工厂模式可以隐藏具体产品类的实现细节,使客户端无需关心具体的产品实现,只需要知道工厂可以创建出所需产品即可。
工厂模式可以分为简单工厂模式、工厂方法模式和抽象工厂模式。
简单工厂模式适用于只有一个工厂类,可以根据输入参数创建不同的具体产品。
工厂方法模式适用于多个工厂类,每个工厂类负责创建一种具体产品。
抽象工厂模式适用于具有多个产品族的结构,每个工厂类负责创建一个产品族。
三、代理模式代理模式是一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。
代理对象可以在不改变原始对象的情况下,对原始对象进行增强或者限制访问。
代理模式有多种实现方式,最常见的是静态代理和动态代理。
静态代理需要手动编写代理类,代理类与被代理类的接口一致,会将请求转发给被代理对象。
动态代理则是在运行时动态创建代理类,可以选择在特定的方法前后加入增强逻辑。
四、观察者模式观察者模式是一种行为型模式,它定义了一种一对多的依赖关系,让多个观察者对象同步地监听一个主题对象,当主题对象发生改变时,会通知所有观察者对象,使它们能够自动更新。
观察者模式由两个核心角色组成,一个是主题(Subject),一个是观察者(Observer)。
主题负责维护对观察者的引用列表,并提供注册/删除观察者和通知观察者的方法。
设计模式分为三大类23种(单例模式)

设计模式分为三⼤类23种(单例模式)1) 创建型模式:单例模式、抽象⼯⼚模式、原型模式、建造者模式、⼯⼚模式。
2) 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3) ⾏为型模式:模版⽅法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)。
单例模式:定义: 所谓类的单例设计模式,就是采取⼀定的⽅法保证在整个的软件系统中,对某个类只能存在⼀个对象实例,并且该类只提供⼀个取得其对象实例的⽅法(静态⽅法)单例模式有⼋种⽅式:1) 饿汉式(静态常量)2) 饿汉式(静态代码块)3) 懒汉式(线程不安全)4) 懒汉式(线程安全,同步⽅法)5) 懒汉式(线程安全,同步代码块)6) 双重检查7) 静态内部类8) 枚举1. 饿汉式(静态常量)步骤如下:1) 构造器私有化 (防⽌new )2) 类的内部创建对象3) 向外暴露⼀个静态的公共⽅法。
getInstance4) 代码实现优缺点说明:1) 优点:这种写法⽐较简单,就是在类装载的时候就完成实例化。
避免了线程同步问题。
2) 缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。
如果从始⾄终从未使⽤过这个实例,则会造成内存的浪费3) 这种⽅式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,在单例模式中⼤多数都是调⽤getInstance⽅法,但是导致类装载的原因有很多种,因此不能确定有其他的⽅式(或者其他的静态⽅法)导致类装载,这时候初始化instance就没有达到lazy loading的效果4) 结论:这种单例模式可⽤,可能造成内存浪费 2 饿汉式(静态代码块)应⽤实例优缺点说明:1) 这种⽅式和上⾯的⽅式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执⾏静态代码块中的代码,初始化类的实例。
懒汉式与饿汉式的区别

懒汉式与饿汉式的区别java设计模式单例模式 ----懒汉式与饿汉式的区别常⽤的五种单例模式实现⽅式——主要: 1.饿汉式(线程安全,调⽤率⾼,但是,不能延迟加载。
) 2.懒汉式(线程安全,调⽤效率不⾼,可以延时加载。
)——其他: 1.双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题,不建议使⽤) 2.静态内部类式(线程安全,调⽤效率⾼。
但是,可以延时加载) 3.枚举式(线程安全,调⽤率⾼,不能延时加载)如何选⽤? ——单例对象占⽤资源少,不需要延时加载 枚举式好于饿汉式 ——单例对象占⽤资源⼤,需要延时加载 静态内部类式好于懒汉式下⾯介绍⼀下 java设计模式单例模式中懒汉式与饿汉式的区别饿汉式:public class Singleton{private static Singleton singleton = new Singleton ();private Singleton (){}public static Singleton getInstance(){return singletion;}}懒汉式:public class Singleton{private static Singleton singleton = null;public static synchronized synchronized getInstance(){if(singleton==null){singleton = new Singleton();}return singleton;}}⽐较:饿汉式是线程安全的,在类创建的同时就已经创建好⼀个静态的对象供系统使⽤,以后不在改变懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的推荐使⽤第⼀种从实现⽅式来讲他们最⼤的区别就是懒汉式是延时加载,他是在需要的时候才创建对象,⽽饿汉式在虚拟机启动的时候就会创建,饿汉式⽆需关注多线程问题、写法简单明了、能⽤则⽤。
设计模式的分类

设计模式的分类设计模式是一种被广泛应用于软件工程领域的最佳实践,它为软件开发提供了一种适用于特定情境下的可重用解决方案,能够提高软件系统的可维护性、可扩展性和可重用性。
设计模式可以分为三大类:创建型模式、结构型模式和行为型模式。
一、创建型模式1. 单例模式单例模式是一种创建型模式,用于确保一个类只有一个实例,并提供全局访问点。
单例模式适用于那些需要唯一的对象来协调系统操作的情况,如配置管理器、日志记录器等。
实现单例模式的方法有饿汉式和懒汉式,其中饿汉式在类加载时就创建了实例,而懒汉式在第一次使用时才创建实例。
2. 工厂模式工厂模式是一种创建型模式,用于将对象的创建过程封装在一个工厂类中,并通过调用工厂类的方法来创建对象。
工厂模式适用于那些需要根据不同条件创建不同对象的情况,如数据库连接池。
实现工厂模式的方法有简单工厂模式、工厂方法模式和抽象工厂模式,其中简单工厂模式将对象的创建过程封装在一个工厂类的静态方法中,而工厂方法模式和抽象工厂模式则通过定义一个抽象的工厂类和具体的工厂类来实现。
3. 原型模式原型模式是一种创建型模式,用于通过克隆(深拷贝或浅拷贝)已有对象来创建新的对象,而不是通过调用构造函数创建。
原型模式适用于那些需要创建大量相似对象的情况,如游戏中的敌人。
实现原型模式的方法有浅拷贝和深拷贝,其中浅拷贝只复制对象的基本类型属性,而深拷贝则复制对象的所有属性。
二、结构型模式1. 适配器模式适配器模式是一种结构型模式,用于将一个类的接口转换成客户端所期望的另一个接口,从而使原本不兼容的类能够协同工作。
适配器模式适用于那些需要使用已有的类库或接口,但这些类库或接口与当前系统不兼容的情况,如国际化(I18N)处理。
实现适配器模式的方法有类适配器模式和对象适配器模式,其中类适配器模式通过多继承实现,而对象适配器模式通过组合实现。
2. 装饰器模式装饰器模式是一种结构型模式,用于动态地给对象添加功能,而不需要修改对象的代码。
userecoilstate 单例

userecoilstate 单例模式1. 介绍userecoilstate 单例模式是一种常见的设计模式,常用于需要在整个应用程序中只有一个实例的情况。
在这种模式下,只能有一个实例,并且全局可访问此实例。
在多线程环境下,它可以保证只有一个实例被创建。
2. 实现userecoilstate 单例模式的实现有多种方式,其中比较常见的方式包括:2.1. 饿汉式通过在类加载的时候就创建实例的方式来实现单例模式。
这种方式的优点是线程安全,但缺点是可能会造成资源浪费。
2.2. 懒汉式通过在第一次获取实例时才创建实例的方式来实现单例模式。
这种方式的优点是节约资源,但缺点是可能存在线程安全问题。
2.3. 双重检查锁式通过在获取实例时进行双重检查锁定的方式来实现单例模式。
这种方式的优点是在多线程环境下能够保证只创建一个实例,并且能够提高性能。
3. 用途userecoilstate 单例模式的用途非常广泛,常见的用途包括:3.1. 数据库连接池在数据库连接池中,通常需要保证只有一个实例,以便节约资源和提高性能。
3.2. 配置文件管理在读取配置文件时,通常也需要保证只有一个实例,以便保证配置的一致性。
3.3. 日志管理在日志管理中,通常也需要保证只有一个实例,以便保证日志的一致性和减少资源消耗。
4. 注意事项在使用userecoilstate 单例模式时,需要注意以下几点:4.1. 线程安全需要保证在多线程环境下能够保证只有一个实例被创建。
4.2. 延迟加载需要根据具体的需求来选择合适的实现方式,以避免不必要的资源浪费。
4.3. 序列化和反序列化在进行序列化和反序列化时,需要特别注意单例模式的实现方式,以避免出现多个实例。
5. 总结userecoilstate 单例模式是一种非常常用的设计模式,在很多情况下都可以发挥重要作用。
在使用单例模式时,需要根据具体的需求来选择合适的实现方式,并且需要注意线程安全、延迟加载和序列化和反序列化等问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单例设计模式-------懒汉式,饿汉式
单例设计模式是一种很常见的设计模式
在这里介绍两种单例设计模式懒汉式与饿汉式
一、先说一说单例设计模式的特点:
>>1.单例设计模式保证一个类只有一个实例。
>>2.要提供一个访问该类对象实例的全局访问点。
二、单例设计模式要点
对一些类来说,只有一个实例是很重要的。
例如很多时候对于某个系统只需要拥有一个全局对象,这样有利于我们协调系统的整体行为。
再比如说某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象
再通过这个单例对象获取这些配置信息。
从而简化了在比较复杂的环境下配置管理。
通过上面的介绍,我们可以知道单例模式最重要的就是要保证一个类只有一个实例并且这个类易于被访问,那么要怎么做才能保证一个类具有一个实例呢?一个全局变量使得一个对象可以被访问,但是这样做却不能防止你实例化多个对象。
一个更好的办法就是,让该类自身负责保存它的唯一实例。
并且这个类保证没有其他的实例可以被创建。
怎样保证一个对象的唯一总结如下:
>>1.为了避免其它程序过多的建立该类的对象,先禁止其它程序建立该类对象实例(将构造器私有化)
>>2.为了方便其它程序访问该类的对象,只好在本类中自定义一个对象,由1可知该对象是static的,并对外提供访问方式。
三、分析举例
在JAVA中单例设计模式
1. 饿汉式如下所示
2.懒汉式如下所示
3.测试是否保证了对象的唯一性:
通过上述测试我们看到的结果:饿汉式和懒汉式都保证了对象的唯一。
到此我们总结两点:
>>1.饿汉式这种方式加载类对象,我们称作:预先加载方式。
>>2.懒汉式这种方式加载类对象,我们称作:延迟加载方式。
问题:上述程序只是在只有主线程一个线程运行下的测试结果,要是在多线程环境下又会出现什么样的结果呢?这里预先说明一下
其实在多线程的环境下,饿汉式是没有问题的,但是懒汉式这种延迟加载的方式会出现线程安全问题的,下面我们通过例子加以说明。
4.在多线程环境下运行饿汉式与懒汉式
以下是测试用例和结果
观察上述的结果我们看到在饿汉式的测试中两个线程所得到的对象时同一个对象,因为@后面的就是对象的HashCode他们相同
保证了对象的唯一性,但是在懒汉式中所得到对象不是同一个对象,因为两个线程所对应的HashCode不同,导致他们不是同一对象。
这是为什么呢?为什么饿汉式就保证了对象的唯一性了而懒汉式却不能保证对象的唯一呢?
这里我们要分析的就饿汉式和和懒汉式那两个对象了Singleton1,与Singleton2了
在ThreadSingleton1与ThreadSingleton2的run方法中是线程运行的代码块,他们分别调用了饿汉式(Singleton1) 与懒汉式(Singleton2)中的getInstance方法。
在饿汉式中在该类的方法getInstance被调用之前,该类的对象已经存在,假设有两个线程(t1,t2)在调用该方法,t1与t2无论怎样调用都不会产生新的对象,因为该对象在方法调用之前就存在了。
是伴随类的生成而生成的。
相反在懒汉式的方法getInstance被调用之前,该类的对象不一定存在(至少在第一次被调用的时候该类的对象不存在),所以他每次调用之前要检测,若对象不存在则生成对象,对象存在则直接返回。
在多线程环境下问题就出现生成对象的时候,假设有两个线程(t1,t2)在调用该方法,考虑这种情况,就是当线程t1检测到该对象不存在的时候,正要准备创建线程(还没创建),而在这个时候CPU切换到t2上执行权交给t2,t2检测到该对象不存在,就生成了对象,t2线程结束了,执行权回到t1上,t1这个时候就不需要判断了,因为开始他判断了的,他就直接向下执行,生成了对象。
这样就导致了该类生成了两个不同的对象,当然这种情况不一定会发生,但这种情况是绝对存在的,也许你运行10000次都不会出现,或许你一运行就会出现该问题。
那么我们要如何解决这个问题呢?从上面的分析我们可以很清楚的看到,就是要控制当一个线程在操作getInstance方法的时候,不要让另一个线程操作该方法,而该该类对象Singleton2的对象model被线程t1与线程t2所共享,我们将共享的资源称作临界资源,把每个线程访问临界资源的那段代码称作临界代码。
在操作系统中我们知道可以通过为临界代码设置信号量,就可以保证安全的访问共享资源。
在JAVA语言中为了实现这种机制,提供了以下两个方面的支持
>>1 为每个对象设置一个“互斥锁”,这表明,在每一个时刻只有一个线程持有该互斥锁,而其他线程若要获得该互斥锁,必须等到该线程(持有互斥锁的线程)将其释放。
>>2 为了使用这个“互斥锁”,在JAVA语言中提供了synchronized关键字,这个关键字即可修饰函数,也可以修饰代码,实际上可以将其理解为就是一个锁,当一个线程执行该临界代码的时候,用synchronized给该线程先上锁,其它线程进不来,当线程代码执行完了的时候有释放该锁,只不过释放锁是隐式的不需要显示的指明,随代码的执行完毕,锁自动的被释放。
在JDK5.0后提供了接口Lock,该接口实现了比synchronized方法和语句可获得更广泛的锁操作,而用该接口就可以显示的指定加锁lock.lock() 和解锁
lock.unlock() (lock为实现了Lock的对象实例)。
所以我们要将getInstance方法上锁,在代码或函数上加关键字synchronized
修改懒汉式Singleton2中的getInstance代码,如下
测试是否懒汉式保证了对象唯一
通过观察我们可以看到保证了对象的唯一,测试成功。
分析代码,其实可以做一些优化操作,将代码上锁操作了后,每次执行都要检测锁,效率不高,其实我们可以这样思考只有在对象被创建的时候我们才上锁,保证对象的唯一,一旦对
象都存在了,以后操作还需要锁嘛,不需要了吧,好吧我们就再次优化代码如下
这里采用双从判定,提高了多线程下操作的效率。
四。
总计
饿汉式
对象预先加载,线程是安全的,在类创建好的同时对象生成,调用获得对象实例的方法反应速度快,代码简练。
懒汉式:
对象延迟加载,效率高,只有在使用的时候才实例化对象,但若设计不当线程会不安全,代码相对于饿汉式复杂,第一次加载类对象的时候反应不快。