其他分享
首页 > 其他分享> > 【六】多线程 —— 共享模型之不可变

【六】多线程 —— 共享模型之不可变

作者:互联网

如果一个对象在不能够修改其内部状态(属性),那么它就是线程安全的,因为不存在并发修改。

比如类用 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 的使用

IntegerDoubleStringDateTimeFormatterString以及基本类型包装类, 都是使用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