Java thread security Summary

Source: Internet
Author: User

Recently I want to sort out and write down some basic java things. This is a summary of knowledge and a pleasure. The outline has been prepared, which can be divided into the following topics: Java thread security, Java garbage collection, Java concurrent package details, Java profile and JVM performance tuning. Write it slowly. I have paid a lot of effort to repost my original jameswxx article. Thank you very much. There is a lot of information about Java thread security on the Internet. I just want to summarize the considerations from my own perspective. Sometimes writing something is very painful and I know something, however, it is not so easy to make it clear in words. I think To Understand Java thread security, we must understand two main points: Java Memory Model and Java thread synchronization mechanism. Especially for the memory model, Java's thread synchronization mechanism is largely set based on the memory model. Later I will write a Java and package-based article that will give a detailed summary of how to use Java and package-based to write highly efficient and secure multi-thread concurrent programs. It is too hasty for the time being, and will be supplemented later.

Java Memory Model
Different platforms have different memory models, but the JVM memory model specifications are uniform. In fact, Java's multi-thread concurrency problems will eventually be reflected in the Java memory model. The so-called thread security is nothing more than controlling the orderly access or modification of a resource by multiple threads. To sum up the Java memory model, we need to solve two main problems: visibility and orderliness. We all know that a computer has a high-speed cache, and not every time the processor processes data, the memory is used. JVM defines its own memory model and shields the memory management details of the underlying platform. For Java developers, it is necessary to understand the visibility and orderliness of multithreading Based on the JVM memory model.
So what is visibility? Multiple Threads cannot communicate with each other. Communication between them can only be performed through shared variables. The Java Memory Model (jmm) specifies that the JVM has the primary memory, which is shared by multiple threads. When a new object is created, it is also allocated to the primary memory. Each thread has its own working memory, which stores copies of some objects in the primary memory, of course, the thread's working memory size is limited. When a thread operates an object, the execution sequence is as follows:
(1) copy the variable from the primary memory to the current working memory (read and load)
(2) execute the code and change the value of shared variables (Use and assign)
(3) Use the working memory data to refresh the content related to the primary storage (store and write)
The JVM Specification defines the operation commands of a thread on the primary storage: read, load, use, assign, store, and write. When a shared variable has copies in the working memory of multiple threads, if a thread modifies the shared variable, other threads should be able to see the modified value, this is the visibility of multithreading.
So what is orderliness? When a thread references a variable, it cannot be referenced directly from the main memory. If the variable does not exist in the thread's working memory, a copy is copied from the main memory to the working memory, this process is read-load, and the thread will reference this copy after completion. When the same thread references this field again, it is possible to obtain a copy of the variable from the primary storage (read-load-use) Again, or directly reference the original copy (use ), that is to say, the order of read, load, and use can be determined by the JVM implementation system.
The thread cannot directly assign values to fields in the primary memory. It will assign the values to the variable copy (assign) in the working memory ), after the completion, the copy of the variable will be synchronized to the primary storage area (store-write). As to when the synchronization will pass, it is determined by the JVM implementation system. with this field, the field is assigned to the working memory from the main memory. This process is read-load, and the thread will reference this copy of the variable after completion, when the same thread repeatedly assigns values to fields, for example:
Java code collection code
For (INT I = 0; I <10; I ++)
A ++;

The thread may only assign values to copies in the working memory and synchronize them to the primary storage zone only after the last assignment. Therefore, the order of assign, store, and weite can be determined by the JVM implementation system. Suppose there is a shared variable X, thread a executes x = x + 1. From the above description, we can know that X = x + 1 is not an atomic operation, and its execution process is as follows:
1. Read the copy of variable X from the primary memory to the working memory.
2 Add 1 to X
3. Write the value after adding X and 1 back to the primary storage.
If another thread B executes x = X-1, the execution process is as follows:
1. Read the copy of variable X from the primary memory to the working memory.
2 minus 1 for X
3. Write the value after X minus 1 to the primary storage.
Obviously, the final x value is unreliable. Assume that X is now 10, thread a is added to 1, and thread B is reduced to 1. On the surface, it seems that the final X is still 10, but this may happen in the case of multithreading:
1: thread a reads x copies from the primary memory to the working memory. The X value in the working memory is 10.
2: thread B reads x copies from the primary memory to the working memory. The X value in the working memory is 10.
3: thread a adds X in the working memory to 1, and the X value in the working memory is 11.
4: thread a submits X to the primary storage, and X is 11 in the primary storage.
5: thread B reduces the X value in the working memory by 1, and the X value in the working memory is 9.
6: thread B submits X to the central primary storage, and X is 9 in the primary storage.
Similarly, X may be 11. If X is a bank account, thread a deposits, and thread B deducts money, this is obviously a serious problem. To solve this problem, ensure that thread a and thread B are executed in an orderly manner, and the addition or subtraction of 1 to each thread is an atomic operation. Take a look at the following code:
Java code collection code
Public class account {

Private int balance;

Public Account (INT balance ){
This. Balance = balance;
}

Public int getbalance (){
Return balance;
}

Public void add (INT num ){
Balance = balance + num;
}

Public void withdraw (INT num ){
Balance = balance-num;
}

Public static void main (string [] ARGs) throws interruptedexception {
Account account = new account (1000 );
Thread a = new thread (New addthread (account, 20), "add ");
Thread B = new thread (New withdrawthread (account, 20), "Withdraw ");
A. Start ();
B. Start ();
A. Join ();
B. Join ();
System. Out. println (account. getbalance ());
}

Static class addthread implements runnable {
Account account;
Int amount;

Public addthread (account Account account, int amount ){
This. Account = Account;
This. Amount = amount;
}

Public void run (){
For (INT I = 0; I <200000; I ++ ){
Account. Add (amount );
}
}
}

Static class withdrawthread implements runnable {
Account account;
Int amount;

Public withdrawthread (account Account account, int amount ){
This. Account = Account;
This. Amount = amount;
}

Public void run (){
For (INT I = 0; I <100000; I ++ ){
Account. Withdraw (amount );
}
}
}
}

The first execution result is 10200, and the second execution result is 1060. The results of each execution are uncertain because the execution sequence of the thread is unpredictable. This is the root cause of Java synchronization. the synchronized keyword ensures that multiple threads are mutually exclusive to synchronization blocks. synchronized, as a means of synchronization, solves the execution orderliness and memory visibility of Java multithreading, the volatile keyword solves the problem of multi-thread memory visibility. It will be detailed later.

Synchronized keyword
As mentioned above, Java uses the synchronized keyword as one of the measures to ensure the execution orderliness of the multi-thread concurrency environment. When a piece of code modifies the shared variable, the Code becomes a mutex or critical section. To ensure the correctness of the shared variable, synchronized indicates the critical section. The typical usage is as follows:
Java code collection code
Synchronized (LOCK ){
Critical code
}

To ensure the security of the bank account, you can operate the account as follows:
Java code collection code
Public synchronized void add (INT num ){
Balance = balance + num;
}
Public synchronized void withdraw (INT num ){
Balance = balance-num;
}

Didn't synchronized be used like this just now:
Java code collection code
Synchronized (LOCK ){
Critical code
}

So what does public synchronized void add (INT num) mean? In this case, the lock is the object of this method. Similarly, if the method is public static synchronized void add (INT num), the lock is the class of the method.
In theory, each object can be used as a lock, but when an object is used as a lock, it should be shared by multiple threads to make sense. In a concurrent environment, it makes no sense to use an unshared object as a lock. Suppose there is such code:
Java code collection code
Public class threadtest {
Public void test (){
Object lock = new object ();
Synchronized (LOCK ){
// Do something
}
}
}

The existence of the lock variable as a lock is meaningless because it is not a shared object at all, and every thread will execute the object lock = new object (). Each thread has its own lock, there is no lock competition at all.
Each lock object has two queues: one is a ready queue and the other is a blocking queue. The ready queue stores the thread to obtain the lock, and the blocking queue stores the blocked thread, when a thread is awakened, it enters the ready queue and waits for CPU scheduling. When thread a first executes the account. when the add method is used, JVM checks whether there are threads waiting in the ready queue of the Lock Object account. If yes, the account lock is occupied because it is the first operation, the account ready queue is empty, so thread A obtains the lock and executes the account. add method. If this happens, thread B will execute the account. the withdraw method, because thread a has obtained the lock and has not been released, so thread B needs to enter the account ready queue and wait until the lock is obtained before it can be executed.
A thread executes the critical code process as follows:
1. Obtain the synchronization lock
2. Clear the working memory
3. Copy the variable copy from the primary storage to the working memory.
4. calculate these variables
5. Write the variable back to the primary memory
6. Release the lock
It can be seen that synchronized not only ensures the concurrency orderliness of multiple threads, but also ensures the memory visibility of multiple threads.

Producer/consumer model
The producer/consumer model is actually a classic Thread Synchronization Model. In many cases, it is not enough to ensure that multiple threads are mutually exclusive to a shared resource operation, there is usually collaboration between multiple threads.
Assume that there is a table with a plate on it, and only one egg can be placed on it. A puts an egg in it. If there is an egg in it, wait until there are no eggs on the plate, and B will take the eggs from the plate. If there are no eggs on the plate, wait until there are eggs on the plate. In fact, the plate is a mutex. Every time you put eggs on the plate, it should be mutually exclusive. In fact, the wait for a is to take the initiative to give up the lock, and B will remind a to put the eggs while waiting.
How to allow threads to actively release locks
It's easy to call the wait () method of the lock. The wait method is from the object, so any object has this method. Look at the code snippet:
Java code collection code
Object lock = new object (); // declares an object as the lock
Synchronized (LOCK ){
Balance = balance-num;
// The synchronization lock is abandoned here, so it is hard to get and give up again
Lock. Wait ();
}

If a thread acquires the lock, enters the synchronization block, and executes lock. Wait (), the thread enters the lock blocking queue. If lock. Y () is called, a thread in the blocked queue is notified to enter the ready queue.
Declare a plate and only one egg can be placed

Java code collection code
Import java. util. arraylist;
Import java. util. List;

Public class plate {

List

Eggs = new arraylist

();

Public synchronized object getegg (){
If (eggs. Size () = 0 ){
Try {
Wait ();
} Catch (interruptedexception e ){
}
}

Object egg = eggs. Get (0 );
Eggs. Clear (); // clear the plate
Y (); // wake up a thread in the blocked queue to the ready queue
System. Out. println ("get eggs ");
Return egg;
}

Public synchronized void putegg (Object egg ){
If (eggs. Size ()> 0 ){
Try {
Wait ();
} Catch (interruptedexception e ){
}
}
Eggs. Add (EGG); // put eggs on the plate
Y (); // wake up a thread in the blocked queue to the ready queue
System. Out. println ("put eggs ");
}

Static class addthread extends thread {
Private plate;
Private object egg = new object ();
Public addthread (plate ){
This. Plate = plate;
}

Public void run (){
For (INT I = 0; I <5; I ++ ){
Plate. putegg (EGG );
}
}
}

Static class getthread extends thread {
Private plate;
Public getthread (plate ){
This. Plate = plate;
}

Public void run (){
For (INT I = 0; I <5; I ++ ){
Plate. getegg ();
}
}
}

Public static void main (string ARGs []) {
Try {
Plate = new plate ();
Thread add = new thread (New addthread (plate ));
Thread get = new thread (New getthread (plate ));
Add. Start ();
Get. Start ();
Add. Join ();
Get. Join ();
} Catch (interruptedexception e ){
E. printstacktrace ();
}
System. Out. println ("test ended ");
}
}
Execution result:
Add HTML code to favorites
Put eggs
Get the eggs
Put eggs
Get the eggs
Put eggs
Get the eggs
Put eggs
Get the eggs
Put eggs
Get the eggs
Test ended

Declare a plate object to be shared by thread a and thread B. Thread a puts eggs and thread B takes eggs. Hypothesis
1. A calls plate. putegg method. In this case, eggs. the size () is 0, so the eggs are successfully placed on the plate, and the notify () method is executed to wake up the thread of the lock blocking queue. At this time, there is no thread in the blocking queue.
2. Another a thread object calls the plate. putegg method. In this case, the eggs. Size () is not 0. When the wait () method is called, it enters the blocking queue of the lock object.
3. At this time, a line B object is created and plate is called. getegg method, eggs. when the size () is not 0, an egg is successfully obtained, and the notify () method is executed to wake up the thread of the lock blocking queue. At this time, the blocking queue has a thread object, after waking up, it enters the ready queue, and the ready queue is one of them, so it immediately gets the lock and starts to put the eggs in the plate. At this time, the plate is empty, so the eggs are successfully put.
4. If thread a is followed, Repeat 2. If the incoming thread B is used, Repeat 3.
The whole process ensures that you can put eggs, take eggs, put eggs, and take eggs.

Volatile keywords
Volatile is a synchronization method provided by Java, but it is lightweight synchronization. Why? Because volatile can only ensure the visibility of the multi-thread memory, it cannot guarantee the orderliness of multi-thread execution. The most thorough synchronization must ensure orderliness and visibility, such as synchronized. No variable modified by volatile will be copied to the working memory, and any modifications will be written in the primary storage in time. Therefore, all threads can immediately see the modification of the variable modified by valatile, but volatile cannot guarantee that the modification of the variable is orderly. What does it mean? Suppose there is such code:
Java code collection code
Public class volatiletest {
Public volatile int;
Public void add (INT count ){
A = a + count;
}
}

When a volatiletest object is shared by multiple threads, the value of A is not necessarily correct because a = a + Count contains several steps, at this time, the execution of multiple threads is unordered, because there is no mechanism to ensure the execution order and atomicity of multiple threads. The significance of volatile is that any thread's modifications to a will be immediately read by other threads, because the main memory is operated directly, and no threads synchronize the working memory and the main memory. Therefore, the use of volatile is limited. In some cases, the volatile variable can be used to replace the lock. To enable the volatile variable to provide ideal thread security, the following conditions must be met simultaneously:
1) write operations on variables do not depend on the current value.
2) the variable is not included in the variant with other variables.
Volatile only guarantees visibility, so volatile is suitable for scenarios with direct assignment, such
Java code collection code
Public class volatiletest {
Public volatile int;
Public void Seta (int ){
This. A =;
}
}

When there is no volatile Declaration, in a multi-threaded environment, the final value of A is not necessarily correct, because this. A = A; this order may be disrupted when it comes to assigning values to a and synchronizing a back to primary storage. If the statement is declared with volatile, the process of reading the primary storage copy to the working memory and synchronizing A to the primary storage is equivalent to an atomic operation. To put it simply, volatile is suitable for this scenario: a variable is shared by multiple threads, and the thread directly assigns a value to this variable. This is a very simple synchronization scenario. At this time, the cost of using volatile will be very small.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.