catalogue
Single thread operation variable
Multiple threads are read-only to variables or variables do not belong to shared resources
Multithreading can read and write variables
A subclass overrides a parent class method to perform an unknown operation
Variables: normal member variables, static member variables, and local variables
① If the variable does not belong to or is not shared by multiple threads, it is thread safe
② Variables are shared by threads; However, there are only read operations, not any write (modify) operations; Thread safe
Thread safety
Single thread operation variable
@Slf4j(topic = "c.SafeThread") public class SafeThread { private List<Integer> list1 = new ArrayList(); // Common member variable private static List<Integer> list2 = new ArrayList(); // Static member variable private final int OP_NUM = 1000; // Number of operations private final void method(){ List<Integer> list3 = new ArrayList(); // local variable for(int i = 0; i < OP_NUM; i++){ list1.add(i); // Add an element to a normal member variable list2.add(i); // Add an element to a static member variable list3.add(i); // Add an element to a local variable list1.remove(0); // Remove an element from a normal member variable list2.remove(0); // Remove an element from a static member variable list3.remove(0); // Remove an element from a local variable } log.debug("Final common member variable list1 capacity {}", list1.size()); log.debug("Final static member variable list2 capacity {}", list2.size()); log.debug("Final local variable list3 capacity {}", list3.size()); } public static void main(String[] args) { SafeThread st = new SafeThread(); st.method(); } }
list1 common member variable, which is a shared resource for the current object
list2 static member variable, which is a shared resource for the current class
list3 local variable, which is a shared resource in method
However, they are only used in one thread (main thread) and are not shared by multiple threads, so they are thread safe
Multiple threads are read-only to variables or variables do not belong to shared resources
@Slf4j(topic = "c.SafeThread0") class SafeThread0{ private static final int THREAD_NUM = 4; // Number of threads private List<Integer> list1 = new ArrayList(); // Common member variable private static List<Integer> list2 = new ArrayList(); // Static member variable public SafeThread0(){ list1.add(1); // Add element to list1 list2.add(2); // Add element to list2 } private void method(List<Integer> list3){ log.debug("Get normal member variable list1 First element {}", list1.get(0)); log.debug("Get static member variable list2 First element {}", list2.get(0)); log.debug("Remove local variables list3 First element {}", list3.remove(0)); // There are write operations here, but they are thread safe } private void method0(){ List<Integer> list3 = new ArrayList(); list3.add(3); method(list3); } public static void main(String[] args) { SafeThread0 sf = new SafeThread0(); for(int i = 0; i < THREAD_NUM; i++){ new Thread(() -> { sf.method0(); }, "t" + i).start(); } } }
The program ends normally
① list1 and list2 belong to shared resources for threads t0 ~ t3, but only read operations, thread safety
② When the list3 thread t0 ~ t3 calls the method, a new method will be created, which is not a shared variable and is thread safe
Thread unsafe condition
Multithreading can read and write variables
@Slf4j(topic = "c.UnsafeThread") public class UnsafeThread { private final int THREAD_NUM = 10; private final int OP_NUM = 1000; private List<Integer> list = new ArrayList(); private void add(){ list.add(1); } private void remove(){ list.remove(0); } private void method(){ for(int i = 0; i < THREAD_NUM; i++){ new Thread(() -> { for(int j = 0; j < OP_NUM; j++){ add(); remove(); } }, "t" + i).start(); } } public static void main(String[] args) { new UnsafeThread().method(); } }
When the number of threads is small and the number of executions is small, exceptions may not be thrown; But these are accidental. It is unsafe for multithreads to read and write variables
A subclass overrides a parent class method to perform an unknown operation
class SafeBefore{ public void method(List<Integer> list){ add(list); remove(list); } private void add(List<Integer> list){ list.add(1); } public void remove(List<Integer> list){ // The parent class exposes internal methods list.remove(0); } } class UnsafeAfter0 extends SafeBefore{ @Override public void remove(List<Integer> list) { // Class override parent method list.remove(0); list.remove(0); } } class Test8{ public static void main(String[] args) { SafeBefore uf = new UnsafeAfter0(); List<Integer> list = new ArrayList(); uf.method(list); } }
class UnsafeAfter1 extends SafeBefore{ @Override public void remove(List<Integer> list) { // Class override parent method new Thread(() -> { // Directly create a new thread to turn the list into a shared resource list.set(1, 1); }, "Unsafe1").start(); } } class Test8{ public static void main(String[] args) { SafeBefore uf = new UnsafeAfter1(); List<Integer> list = new ArrayList(); uf.method(list); } }
① Although there is only one thread in main, the class overrides the parent class method, which is a messy operation; Directly lead to thread insecurity
② A new thread "Unsafe1" is directly created to turn the list into a shared resource. The new thread also writes to the list
Methods in a class, involving specific implementation or thread safety issues; It's best not to expose it and decorate it with private final