【六】多线程 —— 共享模型之不可变
作者:互联网
如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改。
比如类用 final 修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性。
一、日期转换的问题
SimpleDateFormat
不是线程安全的,可能出现 java.lang.NumberFormatException
或者出现不正确的日期解析结果,例如:
public class SimpleDateFormatTest {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
ConsoleUtil.print(sdf.parse("1951-04-21").toString());
} catch (Exception e) {
ConsoleUtil.print(e.toString());
}
}).start();
}
}
}
2021-08-03 14:34:55 Sat Jul 21 00:00:00 CST 1951
2021-08-03 14:34:55 java.lang.NumberFormatException: For input string: "19511951195119511951195119511951.EE441951195119511951195119511951195119511951E41951195119511951195119511951195119511E4"
2021-08-03 14:34:55 Mon Jul 21 00:00:00 CST 178958921
2021-08-03 14:34:55 Sat Jul 21 00:00:00 CST 1951
2021-08-03 14:34:55 java.lang.NumberFormatException: empty String
2021-08-03 14:34:55 java.lang.NumberFormatException: For input string: "19511951195119511951195119511951.EE441951195119511951195119511951195119511951E4"
2021-08-03 14:34:55 Sat Jul 21 00:00:00 CST 1951
2021-08-03 14:34:55 java.lang.NumberFormatException: multiple points
2021-08-03 14:34:55 java.lang.NumberFormatException: For input string: "19511951195119511951195119511951.EE441951195119511951195119511951195119511951"
2021-08-03 14:34:55 java.lang.NumberFormatException: multiple points
使用同步锁虽能解决问题,但带来的是性能上的损失,并不算很好, 加锁耗性能。
如果一个对象在不能够修改其内部状态(属性),因为不存在并发修改,那么它就是线程安全的,这样的对象在Java 中有很多,例如在 Java 8 后,提供了一个新的日期格式化类:
public class SimpleDateFormatTest01 {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
ConsoleUtil.print(dtf.parse("1951-04-21").toString());
} catch (Exception e) {
ConsoleUtil.print(e.toString());
}
}).start();
}
}
}
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
2021-08-03 14:38:16 {},ISO resolved to 1951-04-21
可以看 DateTimeFormatter
的文档:
二、final 的使用
Integer
、Double
、String
、DateTimeFormatter
、String
以及基本类型包装类, 都是使用final来修饰的。
属性用 final
修饰保证了该属性是只读的,不能修改,类用 final
修饰保证了该类中的方法不能被覆盖,防止子类无意间破坏不可变性。
final原理
public class TestFinal {
final int a = 20;
}
字节码:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 20
7: putfield #2 // Field a:I
<-- 写屏障
10: retu
final
变量的赋值通过 putfield
指令来完成,在这条指令之后会加入写屏障
,保证在其它线程读到它的值时不会出现为 0 的情况。
标签:03,14,模型,1951,2021,共享,多线程,08,21 来源: https://blog.csdn.net/weixin_41231928/article/details/119349369