当前位置:网站首页>共享模型之不可变
共享模型之不可变
2022-06-13 09:00:00 【Q z1997】
日期转换的问题
问题提出
下面的代码在运行时,由于 SimpleDateFormat 不是线程安全的
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
log.debug("{}", sdf.parse("1951-04-21"));
} catch (Exception e) {
log.error("{}", e);
}
}).start();
}
有很大几率出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果,例如:
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2084)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at TestDateParse.lambda$test1$0(TestDateParse.java:18)
at java.lang.Thread.run(Thread.java:748)
思路 - 同步锁
这样虽能解决问题,但带来的是性能上的损失,并不算很好:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < 50; i++) {
new Thread(() -> {
synchronized (sdf) {
try {
log.debug("{}", sdf.parse("1951-04-21"));
} catch (Exception e) {
log.error("{}", e);
}
}
}).start();
}
思路 - 不可变
如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改啊!这样的对象在
Java 中有很多,例如在 Java 8 后,提供了一个新的日期格式化类:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
LocalDate date = dtf.parse("2018-10-01", LocalDate::from);
log.debug("{}", date);
}).start();
}
可以看 DateTimeFormatter 的文档:
@implSpec
This class is immutable and thread-saf
不可变对象,实际是另一种避免竞争的方式。
不可变设计
另一个大家更为熟悉的 String 类也是不可变的,以它为例,说明一下不可变设计的要素
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
// ...
}
final 的使用
发现该类、类中所有属性都是 final 的
- 属性用 final 修饰保证了该属性是只读的,不能修改
- 类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性
保护性拷贝
但有同学会说,使用字符串时,也有一些跟修改相关的方法啊,比如 substring 等,那么下面就看一看这些方法是
如何实现的,就以 substring 为例:
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
发现其内部是调用 String 的构造方法创建了一个新字符串,再进入这个构造看看,是否对 final char[] value 做出了修改:
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
结果发现也没有,构造新字符串对象时,会生成新的 char[] value,对内容进行复制 。这种通过创建副本对象来避免共享的手段称之为【保护性拷贝(defensive copy)】
无状态
在 web 阶段学习时,设计 Servlet 时为了保证其线程安全,都会有这样的建议,不要为 Servlet 设置成员变量,这种没有任何成员变量的类是线程安全的
因为成员变量保存的数据也可以称为状态信息,因此没有成员变量就称之为【无状态】
边栏推荐
- System analysis - detailed description
- Completely uninstall PostgreSQL under Linux
- 14. class initialization, default constructor, =default
- Invalid flex layout setting width
- 【QNX Hypervisor 2.2 用户手册】4.5.1 构建QNX Guest
- 【安全】零基础如何从0到1逆袭成为安全工程师
- turf. JS usage
- Top+jstack to analyze the causes of excessive CPU
- Opencv gaussianblur() explanation (Sigma value)
- Cesium common events, including click events, mouse events, and camera movement events
猜你喜欢
CentOS installing MySQL and setting up remote access
关于RSA加密解密原理
顺时针打印个数组
Use of grep
Simulink如何添加模块到Library Browser
Detailed explanation of C language callback function
A solution to create a new EXCEL workbook on win10 computer and change the suffix to xlsm (normally it should be xlsx)
消息中间件
Cesium achieves sunny, rainy, foggy, snowy and other effects
Tutorial (5.0) 02 Management * fortiedr * Fortinet network security expert NSE 5
随机推荐
20211108 能观能控,可稳可测
20211028 调节和跟踪
Tensorflow1.14 corresponds to numpy version
Top+jstack to analyze the causes of excessive CPU
【安全】零基礎如何從0到1逆襲成為安全工程師
网上开户安全吗?新手可以开账户吗?
GBase 常见网络问题及排查方法
JS string method
Drill down to protobuf - Introduction
Judgment of single exclamation point and double exclamation point in JS
【QNX Hypervisor 2.2 用户手册】4.5 构建Guest
[network security penetration] if you don't understand CSRF? This article gives you a thorough grasp
Pop component submission success failure animation
pytorch统计模型的参数个数
Brief description of port, domain communication port and domain service
20211104 为什么相似矩阵的迹相同
20211028 Stabilizability
How to save the video of wechat video number locally?
教程篇(5.0) 03. 安全策略 * FortiEDR * Fortinet 网络安全专家 NSE 5
transforms. ColorJitter(0.3, 0, 0, 0)