Before we talked about the risk of multithreading, one of the most important is security, because of its importance, so in this chapter to explain, then the cause of thread security problems, we will be from the bottom byte code analysis.
First, the problem leads
Look at a piece of code first
PackageCom.roocon.thread.t3; Public classSequence {Private intvalue; Public intGetNext () {returnvalue++; } Public Static voidMain (string[] args) {Sequence Sequence=NewSequence (); NewThread (NewRunnable () {@Override Public voidrun () { while(true) {System.out.println (Thread.CurrentThread (). GetName ()+" "+Sequence.getnext ()); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); }}}). Start (); NewThread (NewRunnable () {@Override Public voidrun () { while(true) {System.out.println (Thread.CurrentThread (). GetName ()+" "+Sequence.getnext ()); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); }}}). Start (); NewThread (NewRunnable () {@Override Public voidrun () { while(true) {System.out.println (Thread.CurrentThread (). GetName ()+" "+Sequence.getnext ()); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); }}}). Start (); }}
Run result: Carefully found that there are two 84, but the code wants the result is that each thread executes each time, on the original basis of adding one. Therefore, this is a thread security issue.
Thread-0 0Thread-1 1thread-2 2... Thread-2 bayithread-1 1thread-0,thread-2,thread-0-thread-85 Thread-2 86
Explain why:
return value++; By bytecode analysis, it is not actually an atomic operation, value = value + 1; First, the value is read, then the value of value is added 1, and the result after Value+1 is assigned to the original value.
If wired thread 1 and thread 2, assume value at this time is 83.
1. Thread 1 reads value 83.
2. Thread 1 adds 1 to value, which is 84, but at this point the CPU is snatched by thread 2, and thread 2 has not had time to assign the computed value to its value.
3. Thread 2 reads the value of value, which is still 83.
4. Thread 2 adds 1 to value, gets 84, the CPU is snatched by thread 1, thread 1 continues to perform the assignment, assigns its computed result value 84 to value, and thread 1 outputs 84.
5. Thread 2 At this time again grabbed the CPU execution, then, it calculates the resulting value 84 is assigned to value, and finally output 84.
Below to view bytecode file validation:
Continue to view the GetNext method of the bytecode file:
These instructions tell us that value++ is not an atomic operation. Where GetField represents the value of this field, Iadd represents a 1 operation on value, and Putfield represents the value assigned to the JIA1 operation.
The meaning of the directive can be viewed: https://www.cnblogs.com/dougest/p/7067710.html
Second, solve the problem
So, how to solve the above problem? How to ensure the security problem of multithreading?
The simplest way is to add a sync lock.
PackageCom.roocon.thread.t3; Public classSequence {Private intvalue; Public synchronized intGetNext () {returnvalue++; } Public Static voidMain (string[] args) {Sequence Sequence=NewSequence (); NewThread (NewRunnable () {@Override Public voidrun () { while(true) {System.out.println (Thread.CurrentThread (). GetName ()+" "+Sequence.getnext ()); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); }}}). Start (); NewThread (NewRunnable () {@Override Public voidrun () { while(true) {System.out.println (Thread.CurrentThread (). GetName ()+" "+Sequence.getnext ()); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); }}}). Start (); NewThread (NewRunnable () {@Override Public voidrun () { while(true) {System.out.println (Thread.CurrentThread (). GetName ()+" "+Sequence.getnext ()); Try{Thread.Sleep (100); } Catch(interruptedexception e) {e.printstacktrace (); }}}). Start (); }}
Operation Result:
Thread-0 0Thread-1 1thread-2 2... Thread-0 bayithread-1 in athread-2in the thread-0 of thethread-1-thread-2 86 Thread-0 87
There are many solutions to the problem of thread safety, because if all the solutions are synchronous locks, then the so-called multithreading concurrency finally becomes serial. So, multithreading makes no sense.
Finally, a summary of the three conditions that generate thread safety issues:
1. Multi-threaded environment.
2. Multiple threads share a resource. such as servlets are not thread-safe. The same instance variable is manipulated in its service method, and if multiple threads are accessing it at the same time, there is a thread-safety issue because multiple threads share the variable.
3. Perform non-atomic operations on threads.
Third, the understanding of JAVAP
Perhaps we rarely use the JAVAP tool, because there are a lot of good anti-compilation tools now, but I am here to introduce this tool is not to use it to decompile, but to see the Java compiler generated for our bytecode, by comparing the bytecode and source code, we can find a lot of problems, A very important function is to understand a lot of compiler internal working mechanism.
Public class Main { publicstaticvoid main (string[] args) { = "abc"; = "OK" +s+ "xyz" +5; SYSTEM.OUT.PRINTLN (ss);} }
Of course you need to compile this class before you decompile: Javac-g Main.java (using the-G parameter is required to use this option when you want to get the output below javap-l)
Once the compilation is complete, we'll look at different effects using different options:
1. Let's take a look at the simplest case without parameters: JAVAP Main:
Without parameters, the public information for the class is printed, including members and methods
We have two knowledge from the above output: if the class does not appear to derive from another class then it is derived from object, and if there is no declaration construction method for the class, then the compiler will generate a default constructor method (without parameters)
2.javap-c Main
The preceding and the output without parameters, the following shows the method of the specific bytecode, from this output we can learn more about the content.
It is easy to see from the code above that although "+" is used in the source program, the "+" is still converted to StringBuilder at compile time. Therefore, we can conclude that in Java, regardless of the way you use string connections, you are actually using the StringBuilder class.
3.javap-l Main
The-l parameter displays the line number and the local variable table
4.javap-p Main
The-p parameter will print extra information for public members and methods, because this class does not have the same output
These parameters can almost make up the most commonly used collection of JAVAP, the most common should be the-C option, because the information can be printed bytecode, the detailed meaning of these bytecode in the Java Virtual Machine specification defined, interested can see the relevant information!
5.javap-s Main
output Internal type signature
6.javap-v Main
Output stack size, number of method parameters
Iv. Configuring the JAVAP command for Eclipse
JAVAP commands are often used to decompile Java-class files, primarily for Java-profiling Tools, when learning thinking in Java because of the need to decompile class files. To see what optimizations and processes the JVM has done with the code we write, for example, I see
When stitching a string using + =. How the JVM is handled.
Don't say much nonsense. The following tutorials are directly on the configuration:
Click the menu bar Run---> External tools---> External tools configurations ... Then for example click on the new
Input:
Name:javap
Locations: Select the location of the Javap.exe file for your JDK
Working Directory: ${workspace_loc}/${project_name}
Arguments:-classpath bin-c ${java_type_name}
Description:${workspace_loc} indicates the path where the workspace is located;
${project_name} indicates the name of the project;
${java_type_name} indicates the class name (full name) of the selected Java file;
The above variables can be selected by the Variablesbutton in the lower right of each column.
(For some other variables the reader is able to understand it by itself)
Arguments:-classpath represents the classpath of the JAVAP named search (bin indicates relative path relative to the project)-C means that the JVM bytecode will be generated here
For example, with:
Then click Run and you may see an error such as the following:
The above error indicates that you have not selected the Java file. Then select a Java file. Click JAVAP to view the results after the anti-compilation. By the way, you may not know the configuration of the JAVAP command to go there to click, see just know to go there click JAVAP:
V. Add the JAVAP command to Idea
If it is much easier to add the JAVAP command to the compiler to view the bytecode file, here's how to add the JAVAP command to idea:
(1) Open the Setting menu,
(2) Find the Extension tool in the tool click Open,
(3) Click the Green Plus button in the upper left corner of the left area to pop up an edit box like this, enter as prompted,
(4) Click OK after completion, click on the setting window of apply and OK, to here has completed the JAVAP command to add,
(5) View the added commands and run: In the code edit area right-external tool extension options can see the command just added, click to execute.
Resources:
"Java concurrent programming and combat" by dragon Fruit College
The principle and practice of Java Concurrent Programming Eight: Causes of thread security problems (JAVAP byte code analysis)