当前位置:网站首页>多线程之不可变对象
多线程之不可变对象
2022-08-08 17:40:00 【七国的天下,我要九十九】
1 日期转换的问题
SimpleDateFormat是线程不安全类,在对线程环境下,会出现错误.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
log.debug("{}", sdf.parse("2022-08-07"));
} catch (Exception e) {
log.error("{}", e);
}
}).start();
}
出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果.
19:10:40.859 [Thread-2] c.TestDateParse - {
}
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 cn.cf.n7.TestDateParse.lambda$test1$0(TestDateParse.java:18)
at java.lang.Thread.run(Thread.java:748)
2 解决方案
1 同步锁
加锁 ,保证每次只有一个线程去执行方法. 能解决问题,但是影响性能效率.
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();
}
2 类不可变
如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改.
以Java8提供的新日期格式化类DateTimeFormatter.
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
LocalDate date = dtf.parse("2022-08-07", LocalDate::from);
log.debug("{}", date);
}).start();
}
将对象置为不可变对象,是一种避免竞争的方式.
3 不可变设计
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修饰了String对象, 且属性都是final的.
- 属性用 final 修饰保证了该属性是只读的,不能修改
- 类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性
保护性拷贝
使用字符串时,也有一些跟修改相关的方法,比如 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,对内容进行复制, 这种通过创建副本对象来避免共享的手段称为 保护性拷贝
边栏推荐
- XDOJ - count the number of positive integers
- DSPE-PEG-FITC,Fluorescein-PEG-DSPE,修饰性PEG磷脂-聚乙二醇-荧光素
- Cyanine5 tetrazine,Cy5 tetrazineCY5四嗪,1427705-31-4
- 从2022投影行业最新报告,读懂2022年家用智能投影仪该怎么选!
- 手机ETF基金开户哪家证券公司好?哪个更安全
- 2.5W 字详解线程与锁了,面试随便问!!
- The new version of squirrel as source change operation
- 【FPGA教程案例47】图像案例7——基于FPGA的RGB图像转化为灰度图实现,通过MATLAB进行辅助验证
- LeetCode_Binary Tree_Medium_515. Find the maximum value in each tree row
- 离线安装 Anaconda + TensorFlow
猜你喜欢
ARP协议详解,小白易懂
DSPE-PEG-NH2,DSPE-PEG-amine,474922-26-4,磷脂-聚乙二醇-氨基科研试剂
spark学习笔记(八)——sparkSQL概述-定义/特点/DataFrame/DataSet
测试/开发程序员停滞不前,倦怠怎么办?突破各种失败和挫折......
arxiv国内镜像——快速下载
离线安装 Anaconda + TensorFlow
uri (url urn 的区别)
[Paper Reading] RAL 2022: Receding Moving Object Segmentation in 3D LiDAR Data Using Sparse 4D Convolutions
win10如何设置定时联网断网辅助自律
【开源教程2】疯壳·开源编队无人机-硬件资源简介
随机推荐
什么是服务网格?在微服务体系中又是如何使用的?
MySQL中怎么对varchar类型排序问题
【NodeJs篇】fs文件系统模块
转载,fragment讲的很好的大佬
Qt——获取文件夹下所有子文件名称
Fluorescein-PEG-CLS,胆固醇-聚乙二醇-荧光素用于缩短包封周期
PNAS最新研究:81%解题率,神经网络 Codex 推开高等数学世界大门
L2-024 部落 (25 分)(并查集)
yarn : 无法加载文件 D:xxx\node_global\yarn.ps1 因为在此系统上禁止运行脚本
KITTI数据集简介(一)—— 传感器介绍
orbslam2实验记录-----稠密建图
[Paper Reading] RAL 2022: Receding Moving Object Segmentation in 3D LiDAR Data Using Sparse 4D Convolutions
Tensorflow教程(五)——MNIST项目提高
手机ETF基金开户哪家证券公司好?哪个更安全
史上最强IDEA工具使用教程,你想要的全都有!
Chapter 20 Source Code File REST API Reference (2)
c语言指针运算
The new version of squirrel as source change operation
请教一个oracle - cdc问题。 设置为 StartupOptions.latest()
DSPE-PEG-Biotin,385437-57-0,磷脂-聚乙二醇-生物素用于生物分子的检测和纯化