Brain map
Four thread safety policies
Thread limit
An object restricted by a thread, which is exclusive to the thread and can only be modified by the thread that owns it
shared read-only
A shared read-only object can be accessed concurrently by multiple threads without additional synchronization, but no thread can modify it
Thread safe object
A thread safe object or container is internally thread safe through the synchronization mechanism, so other threads can access it freely through the public interface without additional synchronization
Guarded object
Guarded objects can only be accessed by acquiring specific locks
Immutable object definition
In Java, there is an object that is safe when published, which is called immutable object.
Immutable objects can be used in multithreading to ensure thread safety
Conditions to be met by immutable objects
- After an object is created, its state cannot be modified
- All fields of the object are of type final
- The object was created correctly (this reference did not escape during object creation)
How to create immutable objects
- Declare the class as final so that it cannot be inherited
- Make all members private so that other classes and objects cannot directly access these members
- No set method is provided for variables
- Declare all mutable members as final so that they can only be assigned once
- Initialize all members through the constructor for deep copy
- In the get method, instead of directly returning the object itself, the object is cloned and a copy of the object is returned
When it comes to immutable objects, we have to mention the final keyword, which can modify classes, methods and variables:
Use the final keyword to define immutable objects
final keyword can modify classes, methods and variables
- Decorated class: cannot be inherited (all methods in the final class will be implicitly declared as final methods)
- Modification method:
1. The locking method is not modified by the inherited class;
2. Improve efficiency (private method is implicitly modified as final method)
- Modifier variable:
Basic data type variable: cannot be modified after initialization
Reference type variable: its reference cannot be modified after initialization
- Modification method parameters: the same as modification variables
Modified variable example
final modifies the basic data type and String: it cannot be modified after initialization (thread safety)
It can be seen that the compilation reports an error. After being modified by final, the basic type and String variables cannot be modified
final modified reference type variable: its reference cannot be modified after initialization, but its value can be modified (thread unsafe)
package com.artisan.example.immutable; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; @Slf4j public class FinalDemo { // Basic data type int uses final modification to verify that the basic data type modified by final cannot be changed private final static int num = 1; // String type uses final modification to verify that the basic data type modified by final cannot be changed private final static String name = "Small craftsman"; // After a reference type is initialized, its reference cannot be modified, but its value can be modified private final static Map<String, Object> map = Maps.newHashMap(); static { map.put("name", "artisan"); map.put("age", 20); map.put("sex", "male"); } public static void main(String[] args) { // The basic data type and String modified by final cannot be changed // Compilation error: the final field finaldemo num cannot be assigned // num = 2; // Compilation error: the final field finaldemo name cannot be assigned // name = "artisan"; // Reference object. This reference cannot point to another object, but the value of the object can be modified map.put("name", "Small craftsman"); log.info("name:{}", map.get("name")); // Verify that the method parameters are modified by final List<String> list = new ArrayList<>(); list.add("I'm a craftsman"); test2(list); } // The basic type of the variable passed in by the final modifier cannot be changed private void test(final int a) { // Cannot modify // The final local variable a cannot be assigned It must be blank and not using a compound assignment // a = 2; log.info("a:{}", a); } // The variable passed in by the final modification method refers to an object. It cannot point to other objects, but the value of the object can be modified private static void test2(final List<String> list) { // Add data list.add("I am artisan"); list.forEach(str ->{ log.info("data:{}",str); }); } }
It should be noted that when final modifies the reference type, although the reference cannot be pointed to another object, the value of the object can be modified. Thread unsafe
Use the tool classes provided in JDK / Guava to create immutable objects
In addition to final, immutable objects can be defined. The Collections class provided by java can also define immutable objects.
-
Collection. In JDK The object passed in by unmodifiablexxx cannot be modified once initialized. XXX can represent collection, List, Set, Map, etc
-
ImmutableXXX in Google's Guava can also represent Collection, List, Set, Map, etc
Collections.unmodifiableXXX example (thread safe)
The results after implementation are as follows:
Thus, use collections The object modified by unmodifiablemap cannot be modified. If you try to modify the value of the object, an exception will be thrown when the program runs.
Follow collections Unmodifiablemap source code
Continue to look at UnmodifiableMap
It mainly changes all update methods of a new collection into throwing exceptions
Guava ImmutableXXX example (thread safe)
package com.artisan.example.immutable; import com.artisan.anno.ThreadSafe; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @ThreadSafe public class GuavaImmutableSetDemo { // Use the classes provided in Guava to define a collection of immutable objects // Immutable list private final static ImmutableList<Integer> list = ImmutableList.of(1, 2, 3); // Immutable set private final static ImmutableSet<Integer> set = ImmutableSet.copyOf(list); // For an immutable map, data needs to be passed in the form of k/v, that is, the odd bit parameter is key and the even bit parameter is value private final static ImmutableMap<String, String> map = ImmutableMap.of("k1", "v1", "k2","v2"); // The immutable map is constructed through the builder call chain private final static ImmutableMap<String, String> map2 = ImmutableMap.<String, String>builder() .put("key1", "value1") .put("key2", "value2") .put("key3", "value3") .build(); public static void main(String[] args) { // If you modify the data in the object, an unsupported operationexception will be thrown // Unable to add new elements, the runtime will throw Java lang.UnsupportedOperationException list.add(4); // Unable to add new elements, the runtime will throw Java lang.UnsupportedOperationException set.add(4); // Unable to add new elements, the runtime will throw Java lang.UnsupportedOperationException map.put("k3", "v3"); // Unable to add new elements, the runtime will throw Java lang.UnsupportedOperationException map2.put("key4", "value4"); } }
The above code is thread safe. During development, if our object can be changed into an immutable object, we try to change the object into an immutable object, so as to avoid thread safety problems.