java并发编程笔记(六)--共享模型之不可变

1.SimpleDateFormat日期类的改进

下面的代码在运行时,由于 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();
}
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.itcast.n7.TestDateParse.lambda$test1$0(TestDateParse.java:18) 
 at java.lang.Thread.run(Thread.java:748) 
19:10:40.859 [Thread-1] c.TestDateParse - {} 
java.lang.NumberFormatException: empty String 
 at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1842) 
 at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110) 
 at java.lang.Double.parseDouble(Double.java:538) 
 at java.text.DigitList.getDouble(DigitList.java:169) 
 at java.text.DecimalFormat.parse(DecimalFormat.java:2089) 
 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.itcast.n7.TestDateParse.lambda$test1$0(TestDateParse.java:18) 
 at java.lang.Thread.run(Thread.java:748) 
19:10:40.857 [Thread-8] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951 
19:10:40.857 [Thread-9] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951 
19:10:40.857 [Thread-6] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951 
19:10:40.857 [Thread-4] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951 
19:10:40.857 [Thread-5] c.TestDateParse - Mon Apr 21 00:00:00 CST 178960645 
19:10:40.857 [Thread-0] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951 
19:10:40.857 [Thread-7] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951 
19:10:40.857 [Thread-3] c.TestDateParse - Sat Apr 21 00:00:00 CST 1951

有很大几率出现 java.lang.NumberFormatException 或者出现不正确的日期解析结果。

jdk8后使用了一个不可变的安全的日期类–DateTimeFormatter

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();
}

这其实就是一种不可变设计。

同样不可变设计的还有String。

2.String类的不可变设计

它的设计如下:

public final class String //类被final修饰,防止子类更改
 
    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 */ hash 设置为私有化,不能更改,且没有set方法
 private int hash; // Default to 0
 
 // ...
 
}

QQ截图20220301190540

String设置了final private 来防止外界来更改变量以及继承了,对于引用对象,String则是直接复制该对象,防止有外界对原引用对象内部的值进行更改。


版权声明:本文为abaidaye原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。