单例模式之怎么实现我的机器人女友
发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,本篇内容介绍了"单例模式之怎么实现我的机器人女友"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!程序代
千家信息网最后更新 2025年01月19日单例模式之怎么实现我的机器人女友程序代码如下:
本篇内容介绍了"单例模式之怎么实现我的机器人女友"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
程序代码如下:
public class GirlFriend {
private String name;
public GirlFriend(String name) {
this.name = name;
System.out.println("机器人女友制作完成");
}
public void smile() {
System.out.println("笑一个 :-)");
}
public void housework() {
System.out.println("去干家务");
}
public void buKeMiaoShu() {
System.out.println(".......");
}
}
操作也很简单,直接创建对象就行了。
public static void main(String[] args) {
GirlFriend girlFriend = new GirlFriend("小丽");
girlFriend.smile();
girlFriend.housework();
girlFriend.buKeMiaoShu();
}
你看,马上就能干活了。
机器人女友制作完成
笑一个 :-)
去干家务
.......
小帅很快发现了一个漏洞,如果材料足够,他能创造无数个对象。
很快,小帅就在黑市上购买了一套材料,回家启动机器,果然制造出了第二个机器人女友。
小帅难掩心中的兴奋,盘算着,再去黑市买几套材料回来,不就能打印很多个"女友"了?
单例模式
创新基因公司的监控系统很快就发现了这个问题,工程师们加班加点在线升级了系统。
他们采用了一种叫做单例模式的设计模式来保证一台机器只能生成一个对象。
更新后的代码如下:
public class GirlFriend {
private static GirlFriend girlFriend;
private String name;
private GirlFriend(String name) {
this.name = name;
System.out.println("机器人女友制作完成");
}
/**
* 对象通过getInstance方法获取
* @param name
* @return
*/
public static GirlFriend getInstance(String name) {
if(girlFriend == null) {
girlFriend = new GirlFriend(name);
}
return girlFriend;
}
public void smile() {
System.out.println("笑一个 :-)");
}
public void housework() {
System.out.println("去干家务");
}
public void buKeMiaoShu() {
System.out.println(".......");
}
}
public static void main(String[] args) {
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
girlFriend.smile();
girlFriend.housework();
girlFriend.buKeMiaoShu();
}
创新基因公司的工程师们很满意,他们开了一个盛大的party,庆祝工作的圆满完成。
小帅花了重金,在黑市上买了好几套材料,打算回家打造一个"后宫团",想想以后的日子真是美滋滋啊。
小帅打开程序一看傻了眼,运行了好多次,获取的都是同一个对象,"后宫"梦就此破裂了吗?
小帅不甘心啊。
经过几天苦思冥想,小帅终于想到了破解方法,这就是多线程:
public static void main(String[] args){
for(int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
GirlFriend girlFriend = GirlFriend.getInstance("小丽");
System.out.println(girlFriend);
}
}).start();
}
}
5个线程同时运行,顺利创建了3个不同的对象。
机器人女友制作完成
singleton.singleton.GirlFriend@95458f7
机器人女友制作完成
机器人女友制作完成
singleton.singleton.GirlFriend@d9d8ad0
singleton.singleton.GirlFriend@383a0ba
singleton.singleton.GirlFriend@d9d8ad0
singleton.singleton.GirlFriend@d9d8ad0
"呜。呜。呜。",创新基因公司的报警器又响了起来,工程师们都一脸懵逼,这么完美的单例模式怎么还有破绽呢?
最后还是技术总监亲自出马,给工程师们讲解,顺便画了一幅图:
线程1和线程2判断girlFriend的时候如果都为空,就会各自创建一个对象,最后就会返回两个不同的对象了。
工程师们恍然大悟。
"谁知道如何改进吗?"技术总监问道。
懒汉式
"这个简单,在getInstance方法上加个synchronized关键字就行了!"程序员老王得意的说。
/**
* 对象通过getInstance方法获取
* @param name
* @return
*/
public synchronized static GirlFriend getInstance(String name) {
if(girlFriend == null) {
girlFriend = new GirlFriend(name);
}
return girlFriend;
}
"这样确实可以,不过,"技术总监话锋一转,"你有没有考虑过效率问题?"
"synchronized同步方法只有第一次创建对象的时候能用到,也就是说一旦创建了girlFriend对象后就用不到这个同步功能了,但是以后每次调用getInstance方法都会进入同步代码,严重降低了效率。"
技术总监犀利地指出了问题所在。
饿汉式
"还有个办法,可以用全局变量,在类加载的时候就创建对象,所以,实例的创建过程是线程安全的。"程序员小李也想出了一个办法。
public class GirlFriend {
// 在类加载的时候就创建对象,是线程安全的
private static GirlFriend girlFriend = new GirlFriend("小丽");
private String name;
private GirlFriend(String name) {
this.name = name;
System.out.println("机器人女友制作完成");
}
/**
* 对象通过getInstance方法获取
* @return
*/
public static GirlFriend getInstance() {
return girlFriend;
}
public void smile() {
System.out.println("笑一个 :-)");
}
public void housework() {
System.out.println("去干家务");
}
public void buKeMiaoShu() {
System.out.println(".......");
}
}
技术总监说:"这是个办法,不过,这样的实现方式有几个问题需要考虑。"
不支持延迟加载(在真正用到对象的时候,再创建实例),在类加载的时候对象就创建好了,如果对象在整个程序中一次都用不到,提前创建就浪费了。
不能控制对象的数量,我们完全可以声明多个对象,比如:GirlFriend girlFriend1;GirlFriend girlFriend2;GirlFriend girlFriend3。
我们可能没有足够的信息在静态初始化时,实例化每一个对象,对象的构造方法参数,可能要依赖程序后面的运算结果。
但是,我们要活学活用,如果创建对象比较耗时,等我们用到的时候再创建就会很慢,我们想在程序加载的时候提前创建好,是可以用这种方式的。
"还有没有其他方法?"技术总监追问道。
双重检测
"还有一种办法,把同步锁放到方法里面,双重检测。"程序员老王想了好久,终于想出了另一种方法。
public class GirlFriend {
// volatile关键字保证了每个线程看到的girlFriend对象都是最新的
private volatile static GirlFriend girlFriend;
private String name;
private GirlFriend(String name) {
this.name = name;
System.out.println("机器人女友制作完成");
}
/**
* 对象通过getInstance方法获取
* @param name
* @return
*/
public static GirlFriend getInstance(String name) {
if(girlFriend == null) {
synchronized (GirlFriend.class) {
if (girlFriend == null) {
girlFriend = new GirlFriend(name);
}
}
}
return girlFriend;
}
public void smile() {
System.out.println("笑一个 :-)");
}
public void housework() {
System.out.println("去干家务");
}
public void buKeMiaoShu() {
System.out.println(".......");
}
}
"检查girlFriend对象的时候,如果为null就进入同步代码,每个线程重新判断girlFriend对象是否为空,volatile关键字保证了每个线程看到的girlFriend对象都是最新的(在高版本的 Java中,这里已经不需要使用volatile了)。"
"如果girlFriend对象已经创建了,以后就不会进入同步代码了,这样就保证了效率。"老王解释道。
"恩,这是个好方法,这样就解决懒汉式方法的低性能和饿汉式方法的延迟加载问题,我们就采用这个方案升级代码吧。"技术总监赞许道。
总结
单例模式(Singleton Pattern):单例模式确保一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式的有三个要点:
某个类只能有一个实例
它必须自行创建这个实例
它必须自行向整个系统提供这个实例
单例模式是一种对象创建型模式。
单例模式又名单件模式或单态模式。
单例的实现单例有下面几种经典的实现方式:
- 懒汉式
懒汉式相对于饿汉式的优势是支持延迟加载。但是,这种实现方式会导致频繁加锁、释放锁,以及并发度低等问题,频繁的调用会产生性能瓶颈。
- 饿汉式
饿汉式的实现方式,在类加载的期间,就已经将静态实例初始化好了,所以,实例的创建是线程安全的。不过,这样的实现方式不支持延迟加载实例。
- 双重检测
双重检测的实现方式是既支持延迟加载、又支持高并发的单例实现方式。只要实例被创建之后,再调用 getInstance() 函数都不会进入到加锁逻辑中。
"单例模式之怎么实现我的机器人女友"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!
对象
方法
模式
机器
女友
机器人
实例
线程
时候
方式
程序
制作
总监
技术
代码
同步
家务
工程
工程师
问题
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
金融业网络安全市场开发策略
无隐私网络安全吗
unity游戏服务器
安卓软件开发学费
初学网络安全吗
java软件开发方向
内网穿透必须要公网服务器吗
湖州云软件开发教程
网络安全保障的通知
芯片行业做软件开发
河南缤果网络技术
如何建立城市地下综合管网数据库
天龙八部所有服务器都可以用吗
专业网络安全认证证书
6g 网络安全愿景
市场监管局强化网络安全工作
网络技术课程简介
设计院网络安全工作总结
普陀区数据软件开发质量保障
坦克世界登陆显示服务器忙
纪检监察网络技术中心
山东工控软件开发怎么样
电厂网络安全总体方案
计算机应用软件开发适合女孩学吗
软件开发 科目
未来科技城有哪些互联网企业
威廉斯特林密码学与网络安全
存储服务器能用多久
清远送货单软件开发
射灯设计软件开发