Once an object is published, it is a secure object, which is an immutable object.
The conditions that an immutable object needs to satisfy:
- The state of an object cannot be modified after it is created
- All fields of an object are final types
- Objects are created correctly (this reference does not escape during object creation)
final keyword: class, method, variable
- Modifier class: cannot be inherited. The member variables in the final class can be set to final as needed. It is important to note that all member methods in the final class are implicitly specified as final methods.
- Modification: 1. Locking methods are not modified by inherited classes; 2. Efficiency
- Modifying variables: Basic data type variables cannot be modified after initialization, and reference type variables cannot point to another object after initialization.
The following example illustrates final modifier variables:
@Slf4j @NotThreadSafe public class ImmutableExample1 { private final static Integer a = 1; private final static String b = "2"; private final static Map<Integer, Integer> map = new HashMap<>(); static { map.put(1, 2); map.put(2, 3); } public static void main(String[] args) { // a = 2; // b = "3"; // map = new HashMap<>(); map.put(1, 3); log.info("{}", map.get(1)); } }
map reference variables cannot specify new references, but they can modify the values inside.
This can lead to thread security issues.
In addition to final defining immutable objects, are there any other means to define immutable objects? Certainly.
- Collections.unmodifiableXX: Collection,List,Set,Map......
- Guava: ImmutableXXX:Collection,List,Set,Map
@Slf4j @ThreadSafe public class ImmutableExample2 { private static Map<Integer, Integer> map = new HashMap<>(); static { map.put(1, 2); map.put(2, 3); map = Collections.unmodifiableMap(map); } public static void main(String[] args) { map.put(1, 3); map.put(3,4); log.info("{}", map.get(3)); } }
This will cause errors in operation:
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableMap.put(Collections.java:1457) at com.vincent.example.immutable.ImmutableExample2.main(ImmutableExample2.java:24)
That is to say, declaring a variable with Collections.unmodifiableMap makes it impossible to modify its content. Data will not be polluted.
@ThreadSafe public class ImmutableExample3 { private final static ImmutableList<Integer> list = ImmutableList.of(1,2,3); private final static ImmutableSet<Integer> set = ImmutableSet.copyOf(list); private final static ImmutableMap<Integer, Integer> map = ImmutableMap.of(1,2,3,4); private final static ImmutableMap<Integer, Integer> map2 = ImmutableMap.<Integer, Integer>builder().put(1,2).put(3,4).build(); public static void main(String[] args) { map2.put(4,5); } }
According to the actual situation of variables, it is best to become immutable objects. If we can try to make the objects immutable, there will be no thread security problems in the case of multi-threading.