Multithreading tutorial (XXIX) immutable design
Common invisibility designs include time formats and string s
Take string 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:
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); }
It is found that it calls the String construction method to create a new String, and then enter this construction 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; } } if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); }
It turns out that neither. When constructing a new string object, a new char[] value will be generated to copy the content. This method of avoiding sharing by creating replica objects is called [protective copy]
3. final principle
public class TestFinal { final int a = 20; }
Bytecode
0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: bipush 20 7: putfield #2 // Field a:I <-- Write barrier 10: return
It is found that the assignment of the final variable will also be completed through the putfield instruction. Similarly, a write barrier will be added after this instruction to ensure that it will not be 0 when other threads read its value
More detailed explanation of final principle:( https://forlogen.blog.csdn.net/article/details/105655338)
In fact, like ordinary assignment, final can be implemented using putfield bytecode instructions, and a write barrier is added after the bytecode to ensure thread safety
The write barrier prevents reordering of instructions
The writing of a final field in any constructor and the subsequent assignment of the reference of this construction object to another reference variable cannot be reordered
Implication: the final field of the object has been properly initialized before the object reference is visible to any thread.
When reading a reference containing the final domain object for the first time, and then reading the final domain for the first time, the two operations cannot be reordered
Implication: the value of the final domain can only be read after the reference containing the final domain object is obtained.