Java Advanced Thread Safety

Source: Internet
Author: User
Tags cas volatile

The atomicity of three core concepts in multithreaded programming

This is similar to the atomic concept of database transactions, where an operation (which may contain more than one sub-operation) is either fully executed (in effect) or is not executed (none).

A very classic example of atomicity is the issue of bank transfers: A and B, for example, transfer $100,000 to C at the same time. If the transfer operation does not have atomicity, a in the transfer to C, read the balance of C is 200,000, and then add 100,000 of the transfer, calculated that there should be 300,000, but also the future and 300,000 write back to the account of C, at this time B's transfer request came over, B found the balance of C is 200,000, and then add 100,000 and write back Then A's transfer operation continues--write 300,000 back to the balance of C. In this case, the final balance of C is 300,000, not the expected 400,000.

Visibility of

Visibility means that when multiple threads concurrently access shared variables, one thread changes the shared variable and other threads can see it immediately. The visibility issue is a point where many people ignore or understand the error.

The CPU's efficiency in reading data from main memory is relatively low, and now there are a few caches in the mainstream computer. When each thread reads a shared variable, the variable is loaded into its corresponding CPU cache, and when the variable is modified, the CPU immediately updates the cache, but does not necessarily write it back to main memory immediately (the time actually written back to main memory is not expected). When other threads (especially those that do not execute on the same CPU) access the variable, the old data is read from the main memory, not the first thread's updated data.

This is an operating system or a hardware-level mechanism, so many application developers often ignore it.

Sequential nature

Sequential means that the order in which the program executes is executed in the order in which the code is executed.

Take the following code as an example

1234 Boolean started = false; //Statement 1 Long counter = 0L; //Statement 2 counter = 1; //Statement 3 started = true; //Statement 4

From the code order, the above four statements should be executed sequentially, but in fact the JVM actually executes this code without guaranteeing that they will be executed exactly in this order.

In order to improve the overall execution efficiency of the program, it is possible to optimize the code by adjusting the code order and executing the code in a more efficient order.

In this case, someone is going to have to worry--what, the CPU doesn't execute code in my Code order, how do we make sure we get the results we want? In fact, you can rest assured that the CPU is not guaranteed to execute exactly in code order, but it will ensure that the results of the final execution of the program and the execution of the code sequence are consistent.

How Java solves multi-threaded concurrency problems How Java guarantees atomic locking and synchronization

A common tool for ensuring the atomicity of Java operations is the locking and synchronization methods (or synchronous code blocks). With locks, you can guarantee that only one thread can get the lock at the same time, and that only one thread can execute the code between the request lock and the release lock at the same time.

123456789 public void Testlock () {lock.lock (); try{Int j = i; i = j + 1;} finally {lock.unlock ();}}

Similar to locks are synchronous methods or synchronized code blocks. When you use a non-static synchronization method, the current instance is locked, and when you use the static synchronization method, the class object is locked, and when you use a static block of code, the object that is synchronized enclosed in parentheses after the keyword is locked. The following is an example of a synchronous code block

123456 public void Testlock () {synchronized (anyobject) {int j = i; i = j + 1;}}

Regardless of the use of locks or synchronized, the essence is the same, through the lock to achieve the nature of the resource, so that the actual target code segment will only be executed by one thread at the same time, thus guaranteeing the atomicity of the target code segment. This is a method at the expense of performance.

CAS (compare and swap)

The underlying type variable self-increment (i++) is an operation that is often mistaken for an atomic operation by a novice and not actually. The corresponding atomic operation class is provided in Java to implement this operation, and guarantees atomicity, which essentially utilizes the CPU-level CAS directives. Because it is a CPU-level instruction, it costs less than the lock that requires the operating system to participate. Atomicinteger use the following method.

12345678 Atomicinteger Atomicinteger = new Atomicinteger (); For (int b = 0; b < numthreads; b++) {New Thread ((), {for(int a = 0 ; a < iteration; a++) {atomicinteger.incrementandget ();}}). Start ();}

How Java guarantees visibility

Java provides volatile keywords to ensure visibility. When you use volatile to modify a variable, it guarantees that the modification of the variable is immediately updated to memory, and that the cache of the variable is invalidated in other caches, so that other threads need to read the value from the main memory to get the most recent value.

How Java guarantees sequential

As explained above, when the compiler and the processor reorder the instructions, the result of the reordering is consistent with the execution of the code order, so the reordering process does not affect the execution of the single-threaded program, but it may affect the correctness of concurrent execution of multithreaded programs.

In Java, the order volatile can be guaranteed by a certain procedure, in addition, by synchronized and locks.

Synchronized and locks guarantee the principle of order and guarantee atomicity, all by guaranteeing that only one thread executes the target code segment at the same time.

In addition to guaranteeing the order of the target snippet execution from the application level, the JVM implicitly guarantees the order by means of the known happens-before principle. The order of execution of two operations, as long as they can be deduced through Happens-before, is guaranteed by the JVM, whereas the JVM makes no guarantees about its order, which can be arbitrarily reordered to get high efficiency.

Happens-before principle (the principle of antecedent occurrence)
    • Delivery rule: If Action 1 precedes action 2 and action 2 precedes action 3, then action 1 will certainly occur before action 3. This rule shows that the happens-before principle is transitive
    • Locking rule: A unlock operation will certainly occur before the lock operation on the same lock is followed. It's good to understand that locks are only released to be retrieved again.
    • Volatile variable rule: a volatile-modified write occurs first in the subsequent read operation of the variable
    • Program Order rules: Within a thread, execute in code order
    • Thread Start rule: the Start () method of the Thread object first occurs on other actions of this thread
    • Thread termination principle: All other operations in the thread that occur after the thread's terminating detection
    • Thread Break rule: The call to the thread interrupt () method occurs first in the acquisition of the interrupt exception
    • Object Finalization rule: An object construct occurs before its finalize
Volatile application Scenarios

Volatile is suitable for scenarios where there is no need to guarantee atomicity, but need to ensure visibility. A typical usage scenario is to use it to decorate a status token that is used to stop a thread. As shown below

12345678910111213 Boolean isrunning = false; public void start () {New Thread ((), {while(isrunning) { Someoperation ();}}). Start ();} public void Stop () {isrunning = false;}

In this implementation, the loop does not necessarily end immediately, even if other threads set IsRunning to False by calling the Stop () method. The volatile keyword can be used to ensure that the while loop gets the latest state of isrunning in time to stop the loop and end the thread.

Thread safety 100,000 Why

Q: In peacetime, the use of locks and synchronized more, and rarely use volatile, there is no guarantee of visibility?
A: Locks and synchronized can guarantee atomicity, and can also guarantee visibility. is achieved by guaranteeing that only one thread executes the target code segment at the same time.


Q: Why do locks and synchronized guarantee visibility?
A: According to the description of the package in the Java doc of JDK 7 concurrent , the write result of one thread guarantees that the read operation of the other thread is visible, as long as the write operation can be inferred by the principle that it happen-before occurs before the read operation.

The results of a write by one thread is guaranteed to is visible to a read by another thread only if the write O Peration Happens-before the read operation. The synchronized and volatile constructs, as well as the Thread.Start () and Thread.Join () methods, can form Happens-before Relationships.

Q: Since locks and synchronized can guarantee atomicity and visibility, why do I need volatile?
A: Synchronized and locks require an operating system to arbitrate who gets the lock, the overhead is high, and the volatile cost is much smaller. Therefore, the performance of using volatile is much higher than using locks and synchronized in situations where visibility is only guaranteed.

Q: Since locks and synchronized can guarantee atomicity, why do we need to atomicinteger this class to ensure atomic operation?
A: Locks and synchronized require the operating system to arbitrate who gets the lock, the overhead is high, and Atomicinteger is the CPU-level CAS operation to ensure atomicity, the overhead is relatively small. So the purpose of using Atomicinteger is to improve performance.

Q: There is no other way to ensure thread safety
Answer: Yes. Avoid conditions that cause non-thread-safe-share variables whenever possible. If you can avoid the use of shared variables from the design, you can avoid the occurrence of non-thread-safe, and it is not necessary to solve the problem of atomicity, visibility, and sequencing through lock or synchronized and volatile.

Q: Synchronized can be modified in a non-static way, can also modify the static method, but also modify the code block, what is the difference
A: When synchronized modifies a non-static synchronization method, the lock is the current instance, while synchronized modifies the static synchronization method, the class object is locked, and when synchronized modifies the static code block, the lock is synchronized The object in parentheses after the keyword.

Java Advanced Thread Safety

Related Article

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.