Java学习-设计模式-单例模式

概述:

单例模式是一种创建模式。
这种模式只涉及一个单独的类,它负责创建自己的对象。
该类确保只创建单个对象。
这个类提供了一种访问其唯一对象的方法。

特点:

  1. 单例模式的构造函数是私有的,没有办法直接使用new调用构造函数,所以不会创建新对象。它只能通过它的一个静态方法得到实例,而这个静态方法可以去调构造函数产生一个实例并返回。
  2. **单例模式的作用 : ** 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问,从而方便地控制了实例个数,并节约系统资源。
  3. **单例模式的使用场合: ** 在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次),应该让这个类创建出来的对象永远只有一个。

理解:

​ 这玩意有点印象,就是某个类不能直接通过构造方法 new 出来,但是可以通过调用这个类中的静态方法返回这个类的对象。在这个类的静态方法中,会判定该类是否已经创建过对象,如果没有则创建,创建过,则返回之前创建的对象。

启动服务器的时候是怎样加载这个单例类的?

摘抄自:阿丙的博客园

 Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。其实所谓的单例模式并不是他的对象永远就只有一个,一个类的对象在我们需要的时候可以随时创建,但是我们不需要管实例的销毁,因为垃圾管理器会自动销毁,这也是java语言的一个特点之一;但是单例模式就是在该类在已经创建一个对象的情况下不允许在创建另一个对象,所以你在使用线程的时候要注意单例类的锁定,不允许2个线程中同时调用一个单例类,应为这2个线程的实例会被创建2次也就是2个不同的实例,这违反了单例模式的约束;在启动服务器的时候该类的实例并没有产生;但是该类会在 java.lang.Class中有一份他自己的字节码。

单例对象的创建与销毁

之前想的是调用就创建了,想要销毁就在类中定义一个方法,将其置为null就OK了,但是百度后得知并不是的。

单例模式并不是它的对象永远就只有一个。而是在该类已经创建一个对象的情况下,不允许再创建另一个对象。所以单例模式的对象并不是在服务启动时创建,在服务停止时销毁。它也是在用到的时候创建,不用的时候销毁。具体就是:服务启动的时候,创建的是类的字节码,在用到时候类加载器读取字节码,生成一个实例,这样就创建出了一个对象。当长时间不使用对象的时候,对象就会被垃圾器回收。下次创建的时候,依然是读取字节码。

当然在类中定义一个方法将其置为null是一个办法;但是没解决根本性问题,因为类未被卸载;并且事实上类的卸载根本不由你控制。

练习举例:

注:该练习参考了程序猿001–单例模式的八种写法比较

  1. **饿汉式(因为对象只存在一个,这里的对象以静态常量存储在类中)(一般情况下可用) **

    优点:这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题。

    缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

    package Practices.Mode.Singleton_Mode;
    // 1.饿汉式(因为对象只存在一个,这里的对象以静态常量存储在类中)(一般情况下可用)
    public class Singleton1 {// 单例对象定义为静态常量public static final Singleton1 singleton1 = new Singleton1(); private Singleton1(){}      // 将构造方法私有化,禁止使用构造方法new出对象public static Singleton1 getSingleton1(){return singleton1;}
    }
    
  2. **饿汉式(这里将对象放到静态代码块中,静态代码块只有在类加载的时候才加载,所以也只会加载一次)(一般情况下可用) **

优点:这种写法比较简单,就是在类加载的时候就完成实例化。避免了线程同步问题。
缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。

package Practices.Mode.Singleton_Mode;
// 2. 饿汉式(这里将对象放到静态代码块中,静态代码块只有在类加载的时候才加载,所以也只会加载一次)(一般情况下可用)
public class Singleton2 {public static Singleton2 singleton2 ;       // 首先还是要定义这个对象static {singleton2 = new Singleton2();          // 在静态代码块中初始化它}private Singleton2(){}                      // 私有化构造方法,避免通过new创建对象public static Singleton2 getSingleton2(){   // 通过Get方法获取对象return singleton2;}
}
  1. **懒汉式(当需要对象时去判断对象存不存在,然后根据情况返回或者创建对象)(线程不安全)(不建议在多线程下使用) **

这种写法起到了Lazy Loading的效果,但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。

package Practices.Mode.Singleton_Mode;
// 3.懒汉式(当需要对象时去判断对象存不存在,然后根据情况返回或者创建对象)(线程不安全)(不建议在多线程下使用)
public class Singleton3 {private static Singleton3 singleton3;       // 首先还是要定义这个对象private Singleton3(){}                      // 在静态代码块中初始化它public static Singleton3 getSingleton3(){   // 通过Get方法获取对象if (singleton3 == null){            // 先判断对象是否存在,不存在则创建,存在则不管singleton3 = new Singleton3();}return singleton3;                      // 返回单例对象}
}
  1. **懒汉式(当需要对象时去判断对象存不存在,然后根据情况返回或者创建对象)(使用线程同步,线程安全)(效率低,不建议在多线程下使用) **

    解决上面第三种实现方式的线程不安全问题,做个线程同步就可以了,于是就对getInstance()方法进行了线程同步。

    缺点:效率太低了,每个线程在想获得类的实例时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面的想获得该类实例,直接return就行了。方法进行同步效率太低要改进。

    package Practices.Mode.Singleton_Mode;
    // 懒汉式(当需要对象时去判断对象存不存在,然后根据情况返回或者创建对象)(使用线程同步,线程安全)(效率低,不建议在多线程下使用)
    public class Singleton4 {private static Singleton4 singleton4;       // 首先还是要定义这个对象private Singleton4(){}                      // 在静态代码块中初始化它public static synchronized Singleton4 getSingleton4(){  // 通过Get方法获取对象if (singleton4 == null){            // 先判断对象是否存在,不存在则创建,存在则不管singleton4 = new Singleton4();}return singleton4;                      // 返回单例对象}
    }
    
  2. **懒汉式(当需要对象时去判断对象存不存在,然后根据情况返回或者创建对象)(虽说有线程限制,但是还是可能创建多个实例)(不建议在多线程下使用) **

    由于第四种实现方式同步效率太低,所以摒弃同步方法,改为同步产生实例化的的代码块。但是这种同步并不能起到线程同步的作用。跟第3种实现方式遇到的情形一致,假如一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。

    package Practices.Mode.Singleton_Mode;
    // 5. 懒汉式(当需要对象时去判断对象存不存在,然后根据情况返回或者创建对象)(虽说有线程限制,但是还是可能创建多个实例)(不建议在多线程下使用)
    public class Singleton5 {private static Singleton5 singleton5;       // 首先还是要定义这个对象private Singleton5(){}                      // 在静态代码块中初始化它public static Singleton5 getSingleton5(){   // 通过Get方法获取对象if (singleton5 == null){            // 先判断对象是否存在,不存在则创建,存在则不管synchronized (Singleton5.class){    // 同步代码块singleton5 = new Singleton5();}}return singleton5;                      // 返回单例对象}
    }
    
  3. **双重检查[推荐用] **

    Double-Check概念对于多线程开发者来说不会陌生,如代码中所示,我们进行了两次if (singleton == null)检查,这样就可以保证线程安全了。这样,实例化代码只用执行一次,后面再次访问时,判断if (singleton == null),直接return实例化对象。

    优点:线程安全;延迟加载;效率较高。

    volatile 关键字:被 volatile 关键字修饰的共享变量(类的成员变量、类的静态成员变量)的属性
    1. 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
    2. 禁止进行指令重排序.
    
    package Practices.Mode.Singleton_Mode;
    // 6.双重检查[推荐用]
    // 这里有一个重要的点,就是 volatile 关键字
    public class Singleton6 {private static volatile  Singleton6 singleton6;       // 首先还是要定义这个对象private Singleton6(){}                       // 在静态代码块中初始化它public static Singleton6 getSingleton6(){  // 通过Get方法获取对象if (singleton6 == null){                // 先判断对象是否存在,不存在则创建,存在则不管synchronized (Singleton6.class){   // 同步代码块if (singleton6 == null) {       // 再次判断对象是否存在,不存在则创建,存在则不管singleton6 = new Singleton6();}}}return singleton6;                      // 返回单例对象}
    }
    
  4. **静态内部类[推荐用] **

    这种方式跟饿汉式方式采用的机制类似,但又有不同。两者都是采用了类装载的机制来保证初始化实例时只有一个线程。不同的地方在饿汉式方式是只要Singleton类被装载就会实例化,没有Lazy-Loading的作用,而静态内部类方式在Singleton类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance方法,才会装载SingletonInstance类,从而完成Singleton的实例化。

    类的静态属性只会在第一次加载类的时候初始化,所以在这里,JVM帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的。

    优点:避免了线程不安全,延迟加载,效率高。

    package Practices.Mode.Singleton_Mode;public class Singleton7 {private Singleton7() {}private static class SingletonInstance {private static final Singleton7 INSTANCE = new Singleton7();}public static Singleton7 getInstance() {return SingletonInstance.INSTANCE;}
    }
    
  5. **枚举[推荐用] **

    package Practices.Mode.Singleton_Mode;public enum Singleton8 {INSTANCE;public void whateverMethod() {}
    }
    

第七和第八个有点蒙,基础还是有点差啊,越学越发现自己好多不知道的。

Java学习-设计模式-单例模式相关推荐

  1. java学习之单例模式(饿汉式与懒汉式)

    ---恢复内容开始--- 设计模式:解决某一类问题最行之有效的方法 java中有23种设计模式 今天学习其中一种:单例设计模式:解决一个类在内存只存在一个对象 想要保证对象唯一. 1.为了避免其他程序 ...

  2. Java学习--设计模式之创建型模式

    一.简介 创建型模式:这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象.这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活.创建型模式包括:工 ...

  3. Java常用设计模式————单例模式

    单例模式简介 90%以上的设计模式都或多或少的应用了接口和抽象类,而单例比较特殊,并没有接口的应用. 单例Singleton指仅仅被实例化一次的类.通常被用来代表那些本质上唯一的系统组件.----&l ...

  4. Java学习 --- 设计模式七大原则的依赖倒转原则

    目录 一.依赖倒转原则 二.依赖倒转原则参考代码 二.依赖倒转原则注意事项 一.依赖倒转原则 1.高层模块不应该依赖低层模块,二者都应该依赖其抽象. 2.抽象不应该依赖细节,细节应该依赖抽象. 3.依 ...

  5. Java学习 --- 设计模式中的UML类图

    目录 一.什么是UML 二.UML图分类 三.UML类图 3.1.依赖关系 3.2.泛化关系 3.3.实现关系 3.4.关联关系 3.5.聚合关系 3.6.组合关系 一.什么是UML 1.UML(统一 ...

  6. java singleton inner class_Java面向对象设计模式-单例模式

    Java面向对象设计模式-单例模式 2020-05-28 589 0 单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点,有多重实现方式. 一.饿汉式单例模式,构造方法私有化,在加载类Sin ...

  7. java/android 设计模式学习笔记(1)--- 单例模式

    前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...

  8. java/android 设计模式学习笔记(1)---单例模式

    前段时间公司一些同事在讨论单例模式(我是最渣的一个,都插不上嘴 T__T ),这个模式使用的频率很高,也可能是很多人最熟悉的设计模式,当然单例模式也算是最简单的设计模式之一吧,简单归简单,但是在实际使 ...

  9. 【设计模式】学习笔记---单例模式

    概述 学习设计模式,死记硬背是没用的,还要从实践中理解 日常应用中,设计模式从来都不是单个设计模式独立使用的.在实际应用中,通常多个设计模式混合使用,你中有我,我中有你.下图完整地描述了设计模式之间的 ...

  10. 我的Java设计模式-单例模式

    就算不懂设计模式的兄弟姐妹们,想必也听说过单例模式,并且在项目中也会用上.但是,真正理解和熟悉单例模式的人有几个呢?接下来我们一起来学习设计模式中最简单的模式之一--单例模式 一.为什么叫单例模式? ...

最新文章

  1. JAVA中的break[标签]continue[标签]用法
  2. 150. 逆波兰表达式求值---JAVA---LeetCode
  3. 嵌入式linux文件系统类型,嵌入式Linux 的Cramfs 根文件系统配置的解决方案
  4. python使用repeat、cycle重复打印字符串
  5. 低版本浏览器如何兼容html5,解决Vue兼容低版本浏览器的简单方法
  6. 滴滴Java实习面经
  7. TCP传输慢问题分析
  8. ubuntu中打开出现闪退_如何解决ubuntu软件中心闪退
  9. 天翼云对象存储android实现,对象存储基础介绍(华为云、腾讯云、天翼云都提供对象存储服务)...
  10. 2020诺贝尔文学奖得主,死亡的诗歌
  11. 真够色!这个AI项目让画师们激动中又透露着瑟瑟发抖!忍不住想尝试
  12. PCB入门使用技巧——个人笔记
  13. 2017寒假作业 计科1501 李俊01
  14. 马化腾:移动互联网上半场接近尾声 腾讯将拥抱产业互联网
  15. stc8a控制MG90S舵机
  16. 安防PPP模式对智慧城市建设的影响和作用
  17. 3本实体书、10个csdn定制笔记本丨20211101期开奖
  18. 笨方法学python3怎么样_在python3中如何实现《笨方法学Python》ex11中的效果
  19. springboot+vue前后端音乐网系统,挺漂亮的
  20. 计算机网络的ios模型,IOS/OSI网络参考模型

热门文章

  1. Win10利用bat文件实现文件与文件夹批量重命名
  2. 基于java廉价房屋租赁管理系统
  3. 2017年全国计算机软件水平考试报名时间和报名入口网址
  4. 【区块链】——区块链学习初探(一)
  5. MD5,SHA1,SHA256,NTLM,LM等Hash在线破解网站收集
  6. 新百家姓前20位(附前300名)
  7. 如何向面试官介绍你的项目(面试技巧)
  8. 计算机是如何计算 log 函数的?
  9. pdf裁边app_PDF切边裁剪(paper for kindle)下载_PDF切边裁剪(paper for kindle)官方下载-太平洋下载中心...
  10. Windows 关闭端口号