Summary: This series of articles focuses on the common problems encountered in high concurrency programming, as well as the underlying implementation principles and usage scenarios of some Java locks.
1. Thoughts triggered by thread safety
The so-called thread safety problem is that in the process of concurrent execution of the program, when multiple threads share the same global variable or static variable to do write operations, data conflict may occur, that is, the thread safety problem. Data conflicts do not occur when the program is read-only. We begin with three questions to address thread-safety issues in concurrent programming.
First question: What is visibility
By definition, visibility is when one thread makes changes to a shared variable, and another immediately gets the updated value. Sample code:
private static boolean flag= true; public static void main(String []args) throws InterruptedException{ new Thread(()-> { while(flag) { } }).start(); Thread.sleep(2000); // create a new Thread to modify the variable new Thread(()->{flag =false; System.out.println(" Thread 2 changed flag to false"); }).start(); }Copy the code
In the code above, if there are no visibility problems, thread 1 will immediately get the result of thread 2’s modification and the program will exit immediately, but the result is that the program will not exit immediately.
Second question: what is atomicity
Atomicity: In one or more operations, either all operations are performed without interruption by other factors, or all operations are not performed.Copy the code
public static int count=0; @Override public void run() { for(int i=0; i<1000; i++){ count ++; } System.out.println(count); } public static void main(String []args){ TestAtomicity testAtomicity = new TestAtomicity(); for(int k=0; k<5; k++){ Thread thread = new Thread(testAtomicity); thread.start(); }}Copy the code
In the above code, we tried to create five threads to increment the count variable and start running the code. The final result of count should be 5000, but this is not the case. This is due to the problem of resource contention in the concurrent environment.
Third question: what is order
Order: Refers to the execution order of the code in the program. Java code is compiled to optimize the code so that the execution order and the order of the code written are not necessarily the code order. High concurrency scenarios were simulated using the Jcstress pressure tool.
Start by introducing the JCStress toolkit into your project:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.openjdk.jcstress</groupId> <artifactId>jcstress-core</artifactId> < version > 0.5 < / version > < / dependency > < the dependency > < groupId > org. Its. Jcstress < / groupId > < artifactId > jcstress - samples < / artifactId > < version > 0.5 < / version > < / dependency >Copy the code
Sample code:
@JCStressTest @Outcome(id= {"-1","5"},expect = Expect.ACCEPTABLE,desc = "good result") @Outcome(id="0",expect = Expect.ACCEPTABLE_INTERESTING,desc = "bad result") @State public class TestOrdering { int count; boolean flag; @Actor public void actor1(I_Result r) { if (flag) { r.r1=count; }else { r.r1=-1; } } @Actor public void actor2(I_Result r) { this.count=5; flag =true; }}Copy the code
In the example code, I_Result is the class in the JCStress package, which returns a default value of 0. This sample calls actor1 and actor2 methods once at high concurrency. The normal logic is that x ends with either -1 or 5. It’s going to cause x to be 0.
Execution Result:
2 matching test results. [OK] synchorizedLearn.TestOrdering (JVM args: [-XX:+HeapDumpOnOutOfMemoryError, -Xms20m, -Xmx20m, -Dfile.encoding=UTF-8, -xx: -tieredcompilation]) Observed State Occurrences of Expectation Interpretation -1 110,851,095 ACCEPTABLE good result 0 13868 ACCEPTABLE_INTERESTING bad result 5 70844788 ACCEPTABLE good result [OK] synchorizedLearn. TestOrdering (JVM args: [-XX:+HeapDumpOnOutOfMemoryError, -Xms20m, -Xmx20m, -dfile.encoding =UTF-8]) Occurrences of Observed state Occurrences of Expectation Interpretation -1 84,874,341 ACCEPTABLE good result 0 ACCEPTABLE_INTERESTING bad result 5 74,437,997 ACCEPTABLE good resultCopy the code
It can be seen from the result that the code has instruction rearrangement in multi-threaded environment.
The summary of this chapter
In multithreaded environment, thread safety mainly includes atomicity, visibility and order. The next chapter introduces the Java Memory Model (JMM) and explores the underlying principles of Synchronized from a Java data structure perspective.