Synchronized__java in the Java SE1.6 of CAS principle

Source: Internet
Author: User
Tags array length cas volatile java se
Synchronized Favorites Summary In the CAS principle Java SE1.6: Synchronized is always the oldest role in multithreaded concurrent programming, and many people call it a heavyweight lock, but as Java SE1.6 has optimized synchronized, and in some cases it's not that heavy, this article describes in detail the bias and lightweight locks introduced in Java SE1.6 to reduce the performance costs of acquiring locks and unlocking locks, as well as the storage structure and upgrade process of locks.

Before JDK 5, the Java language was guaranteed to be synchronized by the Synchronized keyword, which would lead to a lock (and later chapters would also talk about locks).

The lock mechanism has the following problems:

(1) in the multi-threaded competition, lock, release lock will lead to more context switching and scheduling delay, causing performance problems.

(2) A thread holding a lock causes all other threads that require this lock to hang.

(3) If a higher priority thread waits for a lower priority thread to release the lock, the priority is inverted, causing performance risk.

Volatile is a good mechanism, but volatile does not guarantee atomicity. So for synchronization to eventually return to the lock mechanism.

An exclusive lock is a pessimistic lock, and synchronized is an exclusive lock that causes all other threads that need to be locked to hang, waiting for the thread that holds the lock to release the lock. And another more effective lock is the optimistic lock. An optimistic lock is one that completes an operation without a lock but assumes there is no conflict, and retries until it succeeds because of a conflict failure.

CAS operations

The mechanism used for optimistic locking above is cas,compare and Swap.

CAS has 3 operands, memory value V, old expected value A, new value B to modify. If and only if the expected value A and memory value v are the same, the memory value V is modified to B, otherwise nothing is done.

Non-blocking algorithm (nonblocking algorithms)

The failure or suspension of one thread should not affect the failure or suspend algorithm of other threads.

Modern CPUs provide special instructions for automatically updating shared data, and can detect interference from other threads, and Compareandset () uses these instead of locks.

Take out the Atomicinteger to study how the data is correct without a lock.

private volatile int value;

First of all, in the absence of a lock mechanism may need to use the volatile primitives, to ensure that the data between the threads is visible (shared). This allows the value of the variable to be read directly when it is obtained.

Public final int get () {
return value;
}

Then look at how ++i did it.

Public final int Incrementandget () {
for (;;) {
int current = get ();
int next = current + 1;
if (Compareandset (current, next))
return to Next;
}
}

A CAS operation is used here, each time the data is read from memory and then the results of this data and +1 are CAS-operated, and the results are returned if successful, or retry until successful.

And Compareandset uses JNI to complete the CPU instruction operation.

Public final Boolean compareandset (int expect, int update) {
Return Unsafe.compareandswapint (this, valueoffset, expect, update);
}

The whole process is like this, using the CPU of the CAS directive, at the same time using JNI to complete the Java non-blocking algorithm. Other atomic operations are done using similar features.

And the whole j.u.c is built on the CAs, so for the synchronized blocking algorithm, J.U.C has a great improvement in performance.

CAS looks cool, but it can lead to an "ABA problem".

The CAS algorithm implements an important premise that needs to take out the data at some point in memory while comparing and replacing at the next moment, then the time difference will cause the data to change.

For example, a thread one takes out a from memory location V, another thread two also takes out a from memory, and two does something to B, and then two the V position to a, and then one of the CAS operations discovers that the memory is still a, and a operation succeeds. Although the CAS operation for thread one is successful, it does not mean that the process is not a problem. If the header of the list is changed two times, the original value is restored, but does not mean that the list does not change. So the atomic operation Atomicstampedreference/atomicmarkablereference mentioned earlier is very useful. This allows a pair of changed elements to operate atomically.


Extensible reading: http://ifeve.com/java-synchronized/

This article is the author original, the original published in Infoq:http://www.infoq.com/cn/articles/java-se-16-synchronized 1 Introduction

Synchronized has always been an elder role in multithreaded concurrent programming, and many people call it a heavyweight lock, but as the Java SE1.6 is optimized for synchronized, in some cases it is not that heavy, and this article describes in detail the Java Bias and lightweight locks introduced in SE1.6 to reduce the performance costs of acquiring locks and unlocking locks, as well as the storage structure and upgrade process of locks.

2 Term definitions

Terms English Description
Cas Compare and Swap Compare and set. Used to provide atomic operations at the hardware level. In Intel processors, the comparison and exchange is implemented through instruction Cmpxchg. Comparisons are consistent with the given values, and if they are consistent, the inconsistencies are not modified.
3 Basis of the synchronization

Each object in Java can be used as a lock. For synchronization methods, the lock is the current instance object. For static synchronization methods, the lock is the class object for the current object. For a synchronized method block, the lock is an object configured in synchonized brackets.

When a thread attempts to access a synchronized code block, it must first get a lock, and must release the lock when exiting or throwing an exception. So where are the locks? What information is stored inside the lock? 4 Principle of synchronization

The JVM specification requires the JVM to implement method synchronization and code block synchronization based on entry and exit monitor objects, but the implementation details are different. Code block synchronization is implemented using Monitorenter and monitorexit directives, and method synchronization is implemented in a different way, details are not described in detail in the JVM specification, but the synchronization of the methods can also be implemented using these two directives. The monitorenter instruction is inserted at the beginning of the synchronized code block after compilation, and the Monitorexit is inserted at the end of the method and at the anomaly, and the JVM ensures that each monitorenter must have a corresponding monitorexit paired with it. Any object has a monitor associated with it, and when a monitor is held, it is locked. When a thread executes to the monitorenter instruction, it attempts to take ownership of the object's corresponding monitor, which attempts to acquire the object's lock. 4.1 Java Object Header

The lock exists in the Java object's head. If the object is an array type, the virtual machine stores the object header in 3 word (word width), and if the object is a non array type, the object header is stored with a width of 2 characters. In a 32-bit virtual machine, the word width is equal to four bytes, or 32bit.

Length Content Description
32/64bit Mark Word Stores the hashcode or lock information of an object, and so on.
32/64bit Class Metadata Address Pointers stored to object type data
32/64bit Array length The length of the array (if the current object is an array)

In the Java object's head, Mark word hashcode The default storage object, generational age and lock mark Bits. The default storage structure for Mark Word in the 32-bit JVM is as follows:

Bit 4bit 1bit is a bias lock 2bit Lock Sign Bit
No lock state Hashcode of objects Object Generational age 0 01

The data stored in Mark Word will change as the lock flag bit changes during run time. Mark Word may change to store the following 4 types of data:

Lock status

Bit

4bit

1bit 2bit
23bit 2bit Whether it is biased lock Lock sign Bit
Lightweight locks Pointer to lock record in stack 00
Heavy-weight lock Pointer to mutex (heavyweight lock) 10
GC Tags Empty 11
Bias Lock Thread ID Epoch Object Generational age 1 01

Under the 64-bit virtual machine, Mark word is 64bit in size and has the following storage structure:

Lock status

25bit

31bit

1bit

4bit

1bit 2bit
Cms_free Generational age Bias Lock Lock sign Bit
No Locks Unused Hashcode 0 01
Bias Lock ThreadID (54bit) Epoch (2bit) 1 01
4.2 Upgrade of the lock

Java SE1.6 to reduce the performance cost of acquiring locks and releasing locks, the introduction of "bias lock" and "lightweight lock", so in the Java SE1.6 lock a total of four states, no lock state, biased lock state, lightweight lock state and heavyweight lock state, it will gradually upgrade as the competition situation. Locks can be upgraded but cannot be degraded, meaning that a preference lock is upgraded to a lightweight lock and cannot be degraded to a biased lock. This lock escalation strategy, which is not degraded, is designed to improve the efficiency of acquiring locks and unlocking locks, which are analyzed in detail below. 4.3 bias lock

Hotspot's authors have found that in most cases, locks not only have no multi-threaded competition, but are always obtained from the same thread multiple times, in order to allow the threads to obtain a lock at a lower cost and introduce a bias lock. When a thread accesses the synchronization block and acquires the lock, the thread ID of the lock bias is stored in the lock record in the object header and in the stack frame, and the thread does not need to spend the CAS operation to lock and unlock when entering and exiting the synchronization block, but simply test the object header's mark Does Word store a bias lock that points to the current thread? If the test succeeds, indicating that the thread has acquired the lock, and if the test fails, you will need to test to see if the lock-biased identity in Mark Word is set to 1 (indicating that it is currently biased), and if it is not set, use the CAS competitive lock, if set, You try to use CAs to point the tilt lock of the object header to the current thread.

Preference to lock revocation: biased locks use a mechanism that waits until the competition arises to release the lock, so a thread that holds a biased lock will release the lock when other threads try to compete for the lock. The preference for lock revocation requires waiting for the global security point (No bytecode is executing at this point in time), it first pauses the thread that owns the biased lock, and then checks whether the thread holding the biased lock is alive, and if the thread is not active, sets the object header to a lock-free State, and if the thread is still alive, A stack with a bias lock is executed, traversing the lock record of the biased object, the lock record in the stack, and Mark Word in the header of the object is either back to the other thread or back to the unlocked or the marked object is not suitable as a biased lock, and finally wakes the paused thread. The thread 1 in the following figure illustrates the process of biased lock initialization, and thread 2 demonstrates a process that is biased toward lock-undo.

Turn off bias Lock: The bias lock is enabled by default in Java 6 and Java 7, but it is activated several seconds after the application is started, and JVM parameters can be used to turn off delay-xx:biasedlockingstartupdelay = 0 if necessary. If you are sure that all the locks in your application are normally competitive, you can turn off the bias lock-xx:-usebiasedlocking=false with the JVM parameters, and the default is to enter a lightweight lock state. 4.4 Lightweight Lock

Lightweight lock Lock: Before a thread executes a synchronization block, the JVM creates the space in the current thread's stack to store the lock record, and copies the Mark Word in the object header to the lock record, officially called displaced Mark Word. The thread then attempts to use CAs to replace Mark Word in the object header with a pointer to a lock record. If successful, the current thread acquires the lock and, if it fails, indicates that the other thread is competing for the lock, and the current thread attempts to use the spin to acquire the lock.

Lightweight lock unlock: When lightweight unlock, the use of the atomic CAS operation to replace displaced Mark word back to the object header, if successful, indicates no competition occurred. If the failure indicates that the current lock is competitive, the lock expands into a heavyweight lock. The diagram below is a flowchart of two threads vying for locks at the same time, leading to lock expansion.

Since the spin consumes the CPU, in order to avoid unwanted spins (for example, the thread that gets the lock is blocked), once the lock is upgraded to a heavyweight lock, it is no longer restored to the lightweight lock state. When the lock is in this state, the other threads are blocked when they attempt to acquire the lock, and when the thread that holds the lock wakes the thread, the awakened thread will have a new round of lock contention. 5 Lock Advantages and disadvantages comparison

Lock

Advantages

Disadvantages

Applicable scenarios

Bias Lock

Locking and unlocking does not require additional consumption, and the implementation of asynchronous methods is more than a nanosecond-level gap.

If there is a lock competition between threads, it will lead to additional lock-revocation consumption.

Applies to only one thread accessing the synchronization block scene.

Lightweight locks

The competing threads do not block, increasing the response speed of the program.

A thread that does not always have a lock to compete uses a spin that consumes the CPU.

The pursuit of response time.

The synchronization block executes very quickly.

Heavy-weight lock

Thread competition does not use spin and does not consume CPU.

Thread blocking, slow response time.

Pursuit of throughput.

The synchronization block executes more quickly.

6 Reference Source

Some contents of this article refer to the Hotspot source code. Object Header source code MARKOOP.HPP. In favor of lock source BiasedLocking.cpp. As well as other source code ObjectMonitor.cpp and BasicLock.cpp. 7 Reference to the Lock Java-overview-and-java-se6 Synchronization optimization Chapter Dave Dice "Synchronization in Java SE 6" Jav A SE 6 performance White Paper 2.1 Chapter JVM Specification (Java SE 7) Java language Specification (Java SE7) Zhou Zhiming "Deep understanding Java Virtual machine" Java bias Lock implementation principle hotspot Synchroniza tion

If you like this article, please point to praise, share, comment.

Original address: http://ifeve.com/java-synchronized/

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.