猿思考系列3——一文学会思考的正确姿势
看完上一个章节,相信你已经掌握了一些编写并发代码编写的要领了。今天我们来聊一个新的话题。有童鞋反映说之前的两篇思考,内容有些深了,不是太好理解,猿人工厂君决定调整下思路,换个简约点的话题,希望简约而不简单。另外真的很感谢大家的支持,和巨兽的斗争暂时进入僵持阶段,猿人工厂君已经说了,虽千万人,吾往矣。中间细节,猿人工厂君,会在方便的时候公开,程序猿鸭,且行且珍惜。
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式的写法又分为好几种:懒汉模式、饿汉模式、双重锁模式、静态内部类单例模式、枚举模式。接下来就给你show一下各种写法。
package com.pz.se.demo;
public class LanHanSingleton {
private static LanHanSingleton instance;
private LanHanSingleton (){}
public static LanHanSingleton getInstance() {
if(instance == null) {
instance = new LanHanSingleton();
}
returninstance;
}
}
上面这种写法就是懒汉单例模式,特点是类构造器私有,持有自己类型的属性,对外提供获取实例的静态方法,但是线程不安全,延迟初始化,严格意义上讲不算是单例模式。
package com.pz.se.demo;
public class EHanSingleton {
private static EHanSingleton instance = new EHanSingleton();
private EHanSingleton (){}
public static EHanSingleton getInstance() {
returninstance;
}
}
上面的写法就是饿汉单例模式,因为一开始就初始化了,虽然线程安全了,但是可能产生垃圾。
package com.pz.se.demo;
public class SyncSingleton {
private volatile static SyncSingleton singleton;
private SyncSingleton (){}
public static SyncSingleton getSingleton() {
if(singleton == null) {
synchronized (SyncSingleton.class) {
if (singleton == null) {
singleton = new SyncSingleton();
}
}
}
return singleton;
}
}
上面的写法就是双重锁单例模式,这种写法,线程安全,延迟了实例的初始化。这种方式采用双锁机制,线程安全而且在多线程情况下能保持较好的性能。
package com.pz.se.demo;
public class StaticInnerSingleton {
private StaticInnerSingleton(){
}
public static StaticInnerSingleton getInstance(){
return Inner.instance;
}
private static class Inner {
private static final StaticInnerSingleton instance = newStaticInnerSingleton();
}
}
上面这种写法就是静态内部类单例模式,只有在第一次调用公共方法时,JVM才会加载内部内,完成类的初始化化时,得到一个静态对象,供大家使用,这种方式比较常见,也比较推荐。
package com.pz.se.demo;
publicenum EnumSingleton {
INSTANCE;
public static EnumSingleton getInstance() {
return EnumSingleton.INSTANCE;
}
}
上面这种写法就枚举模式,枚举类的方式默认就是线程安全的,隐藏了私有的构造器,在《EffectiveJava》这本书中是推荐写法,不过这样写代码的可读性不是很好。
关于为什么要使用单例模式,很多文章都是这些个观点:一是,解决多线程并发访问的问题。二是节约系统内存,提交系统运行的效率,提高系统性能。然后再扯上static作用域讲个半天。最后得到了千篇一律的解释,然鹅儿这似乎并没有啥卵用,而且很晦涩。
我们回到根本上来,从原理去分析这个问题。一个类由什么组成呢?属性和方法对吧。属性是什么?是变量,是引用,是数据的载体。方法呢?方法其实就是具备一段功能的算法。不要扯经典的数据结构和算法,算法就是解决问题的办法,具有某个功能的方法,他也是算法。那么类这个东西,从结构上讲,分为数据,和算法。
我们从java的内存模型上看,属性承载的数据,在堆内存,方法是在栈内存,而且你要是看了之前讲代码执行套路的文章,那么方法在执行的时候是多线程的方式来执行的。我们在使用方法的时候,很多时候用的是局部变量,没有用类变量,这本身就是为安全性的考虑。
回到为什么用单例模式这个问题上来,答案就很简单了。因为,在这个场景下,我只用使用类的算法。算法支持多线程,已经达到性能要求了。那为什么还有一些配置属性?其实,是当常量来用了,因为,根本就不会改变的情况下,才使用单例。
不信,你翻开你的代码,尤其是用了框架的,你的xxxService放着xxxManager,xxxMabager放着xxxDao,好多就是调用了方法,所以的使用方式是单例的方式,因为你其实只用了类的算法,已经可以看作是常量的数据!
- 【开源】QuickPager ASP.NET2.0分页控件 v2.0.0.2版本。
- 【开源】我的分页控件正式命名为QuickPager ASP.NET2.0分页控件
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——分页控件的源码 (二)
- 高级时钟约束
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——分页控件的源码(一) 主体
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.1——支持多种数据库。让分页更加简单。
- IO约束(下)
- 可以通过基类实现的几种功能。vs2008 .net 2.0
- Python基础知识2:字典
- 桶式移位器
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.7 增加了一个js函数的分页方式。
- FireEye报告:揭露新型工控系统恶意软件TRITON
- 【开源】QuickPager ASP.NET2.0分页控件V2.0.0.6 修改了几个小bug,使用演示。
- Invoke-PSImage:将PS脚本隐藏进PNG像素中并用一行指令去执行它
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 学以致用C++设计模式 “模板方法模式”
- 学以致用C++设计模式 “抽象工厂模式”
- 学以致用C++设计模式 之 “工厂模式”
- 六大原则不熟?那你学什么设计模式?来来来,赶紧来!
- 精品:TCP连接的建立和终止
- python--几种快速排序的实现以及运行时间比较
- TCP/IP详解 -奠基篇
- 段错误?打的就是段错误!!
- (Graph)图,挑着看看
- Mybatis学习笔记(四)调用存储过程
- 跟我一起 自己种一颗 AVL树(平衡二叉搜索树)吧!
- mybatis文件映射之利用collection定义关联集合(五)
- 【奇技淫巧】 -- 原地旋转数组
- mybatis文件映射之利用延迟加载解决collection分布查询(六)
- 【C++】攻克哈希表(unordered_map)