Java设计模式-单例模式(全例记录)

1. 基础介绍

  1. 核心作用:保证一个类只有一个实例,并提供一个访问该实例的全局访问点;
  2. 优点:由于单例模式只生成一个实例,所以减少了系统的开销,当一个系统启动需要较多的资源时,可以直接在系统启动时产生一个单例对象,然后使其永久驻留内存;单例模式可以在系统设置全局访问点,优化共享资源的访问;
  3. 两种主要的单例模式实现方式:饿汉式,懒汉式;

2. 饿汉式介绍

  1. 线程安全,无法延时加载,也就是只要系统一运行,这个单例模式的类对象就会被加载到内存;
  2. 简单步骤:
    首先,将构造器私有化,这样就无法在类的外部直接创建对象;
    然后再类中创建一个本类对象(使用private static修饰,做到全局使用);
    再定义一个getInstance()方法,用来在其它的类中创建单例对象;
    public class Singleton {
        //通过这两个修饰的对象,是线程安全的;
        private static Singleton singleton = new Singleton();
    
        //创建一个私有的构造方法;
        private Singleton() {
        }
    
        //定义一个static方法用来在其它类中获得这个类的实例;
        public static Singleton getInstance() {
            return singleton;
        }
    }
    

3. 懒汉式

  1. 线程安全,延时加载,真正使用时创建;调用的效率比较低(因为每一次调用,都会重新创建一个对象);
  2. 简单步骤:
    首先先创建一个空的类实例,使用private static修饰;
    然后创建一个私有的构造方法;
    最后定义一个加锁的getInstance()方法,用于返回该类的对象;
    public class SingletonDemo {
    //创建一个该类的空对像;
    private static SingletonDemo sing;
    //创建该类的私有构造方法;
    private SingletonDemo(){}
    //创建一个getInstance()方法,用于创建该类的对象;这里用个锁,就可以防止创建多个对象同时被创建;当然,锁也可以放到里面去,放外面可能效率更加低;
    public synchronized static SingletonDemo getInstance(){
        //判断sing对象是否为空,为空则创建;反之,直接输出;
        if(sing==null){
                sing = new SingletonDemo();
            }
            return sing;
        }
    }
    

4. 双重检测锁实现

  1. 上面讲到,可以将synchronized放入到方法里面去,这里就是这样做的,这样可以提高它锁的效率;但是涉及很到jvm底层,目前还没学习,暂做了解;
    大致的步骤与上面一致,我就在懒汉式中直接修改了;
    public class SingletonDemo {
    	//创建一个该类的空对像;
    private static SingletonDemo sing=null;
     //创建该类的私有构造方法;
    private SingletonDemo(){}
     //创建一个getInstance()方法,用于创建该类的对象;
    public static SingletonDemo getInstance(){
       	 //判断sing对象是否为空,为空则创建;反之,直接输出;
       	 if(sing==null){
       	 //在里面进行加锁
            	synchronized (SingletonDemo.class) {
            	 if(sing==null)
            	    sing = new SingletonDemo();
           		 }
        	}
        	return sing;
    	}
    }
    

5. 登记式/静态内部类实现方式

  1. 外部没有static属性,不会像饿汉式一样直接加载对象;只有调用getInstance()方法时加载对象,加载类时,线程安全,因为创建的外部类的对象是static final修饰,导致只有一个实例,只能赋值一次;
  2. 有着饿汉式的高效调用,懒汉式的延时加载;
    基本结构介绍:
    首先先定义一个static的静态内部类,在该类中创建一个外部类的对象,并用private static final修饰该对象;
    创建一个私有化的外部类构造方法;
    最后在外部类中创建一个getInstance方法,用于返回该外部类的对象;
    public class SingleStatic {
    	//创建一个私有的属性;
        private String name = "神";
        //先创建一个该类的私有构造方法;
        private SingleStatic() {
        }
    
    //创建一个静态的内部类;
        private static class SingleInside {
            //定义一个外部类的实例;在内部类中是可以调用外部类的私有构造器的;
            private static final SingleStatic sig = new SingleStatic();
            //我想看看能不能调用外部类的私有属性,可以,很好,
            public static String string(){
                String name=sig.name;
                return name;
            }
        }
    
        //创建一个方法返回该类的对象;
        public static SingleStatic getInstance() {
            return SingleInside.sig;
        }
    
        public static String getname(){
            return SingleInside.string();
        }
    }
    

测试类

class test {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                SingleStatic aStatic = SingleStatic.getInstance();
                System.out.println(aStatic);
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                SingleStatic instance = SingleStatic.getInstance();
                System.out.println(instance);
            }
        }).start();

        System.out.println(SingleStatic.getname());

    }
}

结果输出(符合单例模式):

6. 枚举

  1. 通过枚举实现单例模式,枚举本身就是一种单例模式,无延时加载,线程安全,调用效率高;
    public enum SingleEnum {
        //这就相当与创建好了;
        SINGLE_ENUM;
    }
    

7.总结

很明显,在单例模式中除了枚举的方式之外,其它的方式都可以通过反射的方式,强行获取对象的构造方法;当然也是可以避免的;只需要在创建前再次判断抛出一个异常结束就可以了;还有一些比如反序列化也可以进行破解,这里就不一一记录,感觉这种东西,只要了解,知道怎么规避就可以了,防止反序列化破解的话可以直接使用一个方法 readResolve() ,这个方法原理不是很懂,看别人的博客说是在使用对象流的时候会进行检查,如果有这个方法就会直接返回已有的对象,这个方法的出处没有,仿佛就是自己定义的一样;

Java杂记

a) 内部类可以直接调用外部类包括private的成员变量,构造方法;

b) 而外部类调用内部类需要建立内部类对象,当然,内部类也可以将方法设置为静态的;

热门文章

暂无图片
编程学习 ·

GPS卫星位置计算(卫星位置计算小程序)

目录一、准备以及结果图二、数据三、计算四、全部代码附:一、准备以及结果图软件:eclipse(2020-6版本)带有WindowBuilder插件编程语言:Java结果图:二、数据t0e星历的基准时间单位:秒a_sqrt轨道半长轴的平方根单位:米e1轨道离心率单位:无量纲i0倾角(在 t0e时)单位:r…
暂无图片
编程学习 ·

【考试记录】Apsara Clouder基础技能认证:实现调用API接口

从今天开始,准备把阿里的认证尽可能多的考出来。原因有这么几个:研究生要毕业了,除了把论文写好,还有找工作的压力,所以想尽可能多的考出几个证来证明自己的学习能力;研究生毕业后想找个教师的工作,所以得以身作则,多学习知识,这样教学生才能有底气。知道自己现在能力…
暂无图片
编程学习 ·

线程同步

多线程同步 1)为什么需要多线程同步? 一块资源被多个线程同时操作的时候,当没有人任何操作,每个线程不知道什么时候开始执行什么时候结束,所以最终程序的运行结果会跟预想的不同 2)临界资源 临界区 临界资源:同一时刻只能够允许一个线程去访问的资源 临界区:访问临界资…
暂无图片
编程学习 ·

【GNURadio RTL-SDR】双RTL-SDR信号源的FM调频广播接收机

文章目录1. 前言2. 实验过程2.1 制作流图2.2 RTL-SDR的设备参数1. 前言 两个RTL-SDR的dongle“电视棒”,芯片 RTL2832U + R820T ,淘宝50左右那种能收FM和我国DTMB频段,想都接到同一台电脑去用软件无线电(GNURadio)的方式收多个FM调频广播信号。 2. 实验过程 在谷歌搜了不少…
暂无图片
编程学习 ·

Docker在阿里云上(Centos)下载安装

Docker作用 简单来说就是可以不在考虑项目的运行环境直接转移部署项目,只需要一个镜像文件,甚至可以理解为一个虚拟机(windows的VM软件里安装linux系统)。 卸载旧版本 sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker…
暂无图片
编程学习 ·

C 语言为什么不会过时?

01、为什么C语言不会过时 评价任何一门编程语言,都是招人骂的。永远是这样。就像是春寒料峭的季节,街上穿棉袄和穿单衣的擦肩而过,双方一定是同时在心里出现了两个字:“傻逼!”这个在心理学上有个专业的名字:叫做“二逼”现象! 那我为啥还要做这个挨骂的事呢?作为《C语…
暂无图片
编程学习 ·

windows 搭建es 集群 使用cerebro

1.2.一次修改三个节点下配置文件具体操作:主节点nodecluster.name: my-applicationnode.name: nodenode.master: truenode.attr.rack: r1network.host: 127.0.0.1http.port: 9200transport.tcp.port: 9300discovery.seed_hosts: ["127.0.0.1:9300","127.0.0.1:…
暂无图片
编程学习 ·

Flink原理与实现:Flink中的状态管理,keygroup,namespace

namespace维护每个subtask的状态上面Flink原理与实现的文章中,有引用word count的例子,但是都没有包含状态管理。也就是说,如果一个task在处理过程中挂掉了,那么它在内存中的状态都会丢失,所有的数据都需要重新计算。从容错和消息处理的语义上(at least once, exactly onc…
暂无图片
编程学习 ·

软件测试的基本流程

软件测试的基本流程 1. 测试需求分析阶段阅读需求 理解需求 主要就是对业务的学习 分析需求点 参与需求评审会议2. 测试计划阶段主要任务就是编写测试计划 参考软件需求规格说明书 项目总体计划,内容包括测试范围(来自需求文档),进度安排,人力物力的分配,整体测试策略的制…
暂无图片
编程学习 ·

windows10系统-2-安装Nodejs及SocketIO

(1)双击node-v12.14.1-x64.msi CMD>npm --version查看npm的版本 CMD>npm -v (2)使用淘宝镜像的命令 CMD>npm install -g cnpm --registry=https://registry.npm.taobao.org CMD>npm list -g查看所有全局安装的模块 【全局安装所在路径C:\Users\user\AppData\Roamin…
暂无图片
编程学习 ·

集合类

Collection集合: 集合是Java提供的一种容器,可以用来存储多个数据。数组也是容器,但是数组的长度是固定的,集合的长度是可变的 数组中存储的都是同一类型的元素,可以存储基本数据类型的值;集合存储的都是对象,而且对象的类型可以不一致。 在开发中,一般对象多的时候,使…
暂无图片
编程学习 ·

java6----break与continue

1:continue的例子 package java1;public class java3 {public static void main(String[] args) {for (int i = 1; i <= 20; i++) {if (i % 4 == 0) {continue;//跳过本轮循环 ,也就是跳过下面的输出,进行下一次的for循环}System.out.print(i + " ");}} } /* 1…
暂无图片
编程学习 ·

数独小游戏开发(1)---自定义界面

放假闲着没事,自己写个小游戏练练手平时看到的数独小游戏的界面都是直接一个999\times999的小方格,这里使用自定义View实现。 重写onDraw()实现自定义界面的显示@Overridepublic void onDraw(Canvas canvas) { // super.onDraw(canvas);//浅色线条Paint grayPaint = n…
暂无图片
编程学习 ·

FRM考场的这些注意事项,估计你还不知道!

1、FRM一二级考试时,会提前15分钟关闭考场,请考生务必提前到达考场。 2、FRM准考证一定要是纸质的,其他类型将不受认可。打印需保持纸张整洁。 3、FRM发放试卷期间注意聆听监考老师讲述的FRM考试规则。提前看卷和答卷视为违规。 4、FRM考试最后半小时不允许出入考场,任何出…
暂无图片
编程学习 ·

计算机专业大学生的随感

我想去聚会,想和朋友一起喝酒,但是仔细一想,自己好像没有可以去的聚会,也没有可以陪着自己喝酒的朋友。 懒得在社交上花费时间和精力,那么需要朋友的时候,就只能对着屏幕空感叹。 那几分GPA虽然重要,但真的不至于占用自己那么多时间
暂无图片
编程学习 ·

冒泡排序

冒泡排序 public class Test{public static void main(String[] args){int[] arr = {20,5,15,10,0,25};int temp = 0;for (int j=0;j<arr.length-1;j++ ){for (int i=0;i < arr.length-1-i ;i++ ){if (arr [i] > arr [i+1]){temp = arr [i+1];arr [i+1] = arr [i];arr…
暂无图片
编程学习 ·

String类、Arrays类

String类 概念:之前都已经接触到了String的对象,是一个字符串。String类就代表的是字符串 特点 1.双引号引起来的"abc",这种也是String对象,这种对象不是保存到堆中而是方法区的常量池中 2.字符串对象是不可变的对象,只要你观察到字符串的内容变化了,那么肯定是…
暂无图片
编程学习 ·

Vue循环渲染&key的原理

v-for用于循环的数组里面的值可以是对象,也可以是普通元素<ul id="example-1"><!-- 循环结构-遍历数组 item 是我们自己定义的一个名字 代表数组里面的每一项 items对应的是 data中的数组--><li v-for="item in items">{{ item.mess…
暂无图片
编程学习 ·

SpringBooot框架整合MyBatis框架

SpringBooot框架整合MyBatis框架 1.MyBatis框架概述 Mybatis是一个优秀的持久层框架,底层基于JDBC实现与数据库的交互。并在JDBC操作的基础上做了封装和优化,它借助灵活的SQL定制,参数及结果集的映射方式,更好的适应了当前互联网技术的发展 2.初始配置 2.1.在pom.xml文件中…