【单例】JAVA中的单例
单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例。
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
那么如何实现一个单例呢?单例的实现方式有饿汉,懒汉式。懒汉也好,饿汉也好,实现单例的要点就在于让构造方法私有,然后提供公有的静态的方法,对外返回单例的对象实例。懒汉和饿汉的区别在于创建单例对象的时机,一个在类加载时就创建了,一个在调用newInstence方法时才创建。所以,饿汉时实现更为简单,不需要考虑线程安全,但是懒汉式要考虑线程的安全问题。
饿汉式:
public class CatHModel {private String name;private static final CatHModel cat = new CatHModel("Tom");private CatHModel(String name) {this.name = name;}public String getName() {return this.name;}public static CatHModel newInstence(String name) {return cat;} }
final确保了私有变量cat永远指向一开始创建的名为“Tom"的对象。构造方法私有,无法通过new的方式创建对象。
CatHModel cat = CatHModel.newInstence(); CatHModel cat1 = CatHModel.newInstence(); System.out.println(cat == cat1);
输出为
true
Process finished with exit code 0
可见得到的两个对象地址一致,也就是实际指向的是同一个对象。
懒汉式(线程安全)
public class CatFModel {private String name;private static CatFModel cat;private CatFModel() {}public String getName() {return this.name;}public void setName(String name) {this.name = name;}public static CatFModel newInstence() {if (cat == null) {synchronized (CatFModel.class) {if (cat == null) {cat = new CatFModel();}}}return cat;} }
我们来测试一下
List<CatFModel> list = Collections.synchronizedList(new ArrayList<>()); int size = 5; CountDownLatch countDownLatch = new CountDownLatch(size); for (int i = 0; i < size; i++) {final int temp = i;new Thread(() -> {String name = "Sam" + temp;CatFModel catFModel = CatFModel.newInstence();catFModel.setName(name);list.add(catFModel);countDownLatch.countDown();}).start(); } try {countDownLatch.await(); } catch (InterruptedException e) {e.printStackTrace(); } list.forEach(e -> System.out.println(e.getName()));
输出为:
Sam1
Sam1
Sam1
Sam1
Sam1
Process finished with exit code 0
打印的是最后一个线程set的name,因为多个线程使用的是同一个实例,所以最后得到的名字是一样的。多线程下能够保证安全。
但是以上方式实现的单例有一个问题,就是如果通过反射的方式是能够调用私有构造方法创建新对象的。
CatHModel cat = CatHModel.newInstence(); System.out.println(cat.getName()); Constructor constructor = CatHModel.class.getDeclaredConstructor(String.class); constructor.setAccessible(true); CatHModel cat2 = (CatHModel) constructor.newInstance("Henry"); System.out.println(cat2.getName());
输出为:
Tom
Henry
Process finished with exit code 0
通过枚举实现单例模式:
public enum CatEnum {INSTANCE;private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public static CatEnum getInstance(){return INSTANCE;} }
再来试一下
List<CatEnum> list = Collections.synchronizedList(new ArrayList<>()); int size = 5; CountDownLatch countDownLatch = new CountDownLatch(size); for (int i = 0; i < size; i++) {final int temp = i;new Thread(() -> {String name = "Sam" + temp;CatEnum catEnum = CatEnum.getInstance();catEnum.setName(name);list.add(catEnum);countDownLatch.countDown();}).start(); } try {countDownLatch.await(); } catch (InterruptedException e) {e.printStackTrace(); } list.forEach(e -> System.out.println(e.getName()));
输出为
Sam4
Sam4
Sam4
Sam4
Sam4
Process finished with exit code 0
那我们再试一下
Constructor constructor = CatEnum.class.getDeclaredConstructor(String.class,int.class); constructor.setAccessible(true); CatEnum cat2 = (CatEnum) constructor.newInstance(); System.out.println(cat2.getName());
输出
Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.base/java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:544)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:496)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483)
at java_problems.day3.test.main(test.java:67)
会报错,我们看一下具体代码
代码到这里就点不进去了,但是我们看到上面的注释,保证反射的类不是一个枚举类,所以JAVA底层帮助我们做了限制,使得我们无法通过反射的方式破坏单例。
【单例】JAVA中的单例相关推荐
- 笔记:Java中的单例设计模式
之前接触过单例模式,当初不明白这样的设计用意,今天特地研究了下java中的单例设计模式的用处及用法. 单例模式:单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.一个类 ...
- Wordcounter,使用Lambdas和Fork / Join计算Java中的单词数
这些天来,我发布了Wordcounter ,这是一个Java库和命令行实用程序,用于对文本文件中的单词进行计数并对单词计数进行分析,从而大量使用了功能编程结构和并行计算方法. 这是我在"令人 ...
- Java基础题37:(单选题)java中char类型的取值范围是() A.0 ... 32767 B.0 ... 65535
37.(单选题)java中char类型的取值范围是() A.0 - 32767 B.0 - 65535 C.–256 - 255 D.–32768 - 32767 [正确答案]B [答案解析]在jav ...
- java中的单例_细说Java中的几种单例模式
在Java中,单例模式分为很多种,本人所了解的单例模式有以下几种,如有不全还请大家留言指点: 饿汉式 懒汉式/Double check(双重检索) 静态内部类 枚举单例 一.饿汉式 image 饿汉式 ...
- java中''和单双引号有什么区别
区别1:java中的单引号表示字符,java中的双引号是字符串. 区别2:单引号引的数据一般是char类型的:双引号引的数据 是String类型的. 区别3:java中单引号里面只能放一个字母或数字或 ...
- 浅谈:数据结构之单链表,java代码演示单链表
单链表 本文是观看尚硅谷韩老师视频学习总结,部分来源网络. 单链表介绍 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的.链表由一系列结点(链表中每 ...
- Java中的单例设计模式
什么是单例设计模式 所谓单例设计模式,就是采取一定的方法保证整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法. 目的:使用着在main方法中就不可以自己创建实例对象 ...
- java中的单例模型
参考网址:http://www.runoob.com/design-pattern/singleton-pattern.html 1.目的:保证一个类仅有一个实例,并提供一个访问它的全局访问点.(比如 ...
- java中白盒测试用例_基于JAVA开发的中国象棋游戏的开发与研究白盒测试用例.doc...
中国象棋白盒测试用例 文件状态当前版本V1.0草稿 作 者梁世聪完成日期2012/6/17文档模板SSP-VER-T13-V1.0密 级变更历史 版本完成日期变更记录作者批准签字V1.02012/6/ ...
最新文章
- (C++)1023 组个最小数 简单贪心
- Idea-LifecycleException when deploying
- Ruby Fiber指南(三)过滤器
- 前端笔记-StackedBar3D的初步修改(添加legend等)
- Spring Cloud Gateway (六) 自定义 Global Filter
- 微信工程师为你讲述春晚红包的系统设计和优化
- tushare pro积分规则
- oracle建表插数据
- 雷达散射截面(RCS)
- 台式计算机如何取消屏幕密码,台式电脑怎么取消锁屏?
- 系统架构设计师-软件架构设计
- 离了加多宝 第三季好声音将“变味”
- python 对象的销毁_销毁类python的对象
- cesium添加填充_项目中的一个关于cesium的边界线的问题
- 可爱女生开糖果花店,她两年时间就挣了一百万元
- 语音信号的梅尔频率倒谱系数(MFCC)的原理讲解及python实现
- 启用群晖 Drive 的团队文件夹
- mybatis SQL打印插件
- Python下的TK(一)概述
- Linux Power supply子系统分析