6, Immutability of shared model
Contents of this chapter
- Use of immutable classes
- Immutable class design
- Stateless class design
6.1 date conversion
1. Questions raised
The following code is not thread safe at run time because SimpleDateFormat
private static void test01() { 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(); } }
There is a high probability of java.lang.NumberFormatException or incorrect date resolution results, such as:
12:02:00.338 c.Test1 [Thread-2] - {} 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.Test1.lambda$test01$1(Test1.java:31) at java.lang.Thread.run(Thread.java:748) 12:02:00.338 c.Test1 [Thread-0] - {} 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:1869) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514) at java.text.DateFormat.parse(DateFormat.java:364) at cn.itcast.n7.Test1.lambda$test01$1(Test1.java:31) at java.lang.Thread.run(Thread.java:748) 12:02:00.337 c.Test1 [Thread-6] - Fri Apr 21 00:00:00 CST 1195 12:02:00.337 c.Test1 [Thread-4] - Fri Apr 21 00:00:00 CST 1195 12:02:00.337 c.Test1 [Thread-7] - Sat Apr 21 00:00:00 CST 1951 12:02:00.337 c.Test1 [Thread-8] - Sat Apr 21 00:00:00 CST 1951 12:02:00.337 c.Test1 [Thread-5] - Fri Apr 21 00:00:00 CST 1195 12:02:00.337 c.Test1 [Thread-9] - Sat Apr 21 00:00:00 CST 1951 12:02:00.337 c.Test1 [Thread-3] - Fri Apr 21 00:00:00 CST 1195 12:02:00.337 c.Test1 [Thread-1] - Fri Apr 21 00:00:00 CST 1195
2. Idea - synchronous lock
3. Ideas - immutable
If an object cannot modify its internal state (properties), then it is thread safe, because there is no concurrent modification! There are many such objects in Java. For example, after Java 8, a new date formatting class is provided:
public static void test02() { DateTimeFormatter stf = DateTimeFormatter.ofPattern("yyyy-MM-dd"); for (int i = 0; i < 10; i++) { new Thread(() -> { TemporalAccessor parse = stf.parse("1951-04-21"); log.debug("{}", parse); }).start(); } }
You can see the source code of DateTimeFormatter
6.2 immutable design
6.2.1 design of string class
Another more familiar String class is also immutable. Take it as an example to illustrate the elements of immutable design
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 // ... }
1. Use of final
It is found that the class and all attributes in the class are final
- The attribute is decorated with final to ensure that the attribute is read-only and cannot be modified
- Class is decorated with final to ensure that the methods in this class cannot be overwritten and prevent subclasses from inadvertently destroying immutability
2. Protective copy
However, some students will say that when using strings, there are also some methods related to modification, such as substring. Let's take substring as an example to see how these methods are implemented:
public String substring(int beginIndex) { //Conduct verification 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); }
It is found that the constructor of String is called to create a new String, and then enter this constructor to see whether the final char[] value has been modified:
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; } } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } //Copy generates a new array this.value = Arrays.copyOfRange(value, offset, offset+count); }
It was found that neither. When constructing a new string object, a new char[] value will be generated to copy the content. This means of avoiding sharing by creating replica objects is called [protective copy]
*Enjoy the yuan of mode
reference resources "JUC concurrent programming - mode" protective pause mode | sequence control mode | producer consumer mode | two-stage termination mode | Balking mode | sharing mode
Principle final
6.3 stateless
When learning in the web stage, in order to ensure its thread safety when designing servlets, there will be such suggestions. Do not set member variables for servlets. Such classes without any member variables are thread safe
Because the data saved by member variables can also be called status information, it is called stateless if there is no member variable
difference
- Immutable: it has members and states, but it cannot be changed. It is thread safe
- Stateless: no member, stateless, immutable Lou, thread safe
Summary of this chapter
Use of immutable classes
Immutable class design
- Principle aspect
- final
- Mode aspect
- Enjoy yuan