Talk about synchronized in Java concurrency

1 Introduction

Synchronized has always been a veteran role in multithreaded concurrent programming. Many people will call it heavyweight lock, but with the development of Java SE1 6 after various optimizations on synchronized, it is not so heavy in some cases. This article introduces Java SE1 in detail In order to reduce the performance consumption caused by obtaining and releasing locks, biased locks and lightweight locks are introduced in 6, as well as the storage structure and upgrade process of locks.

2 definition of terms

3 basis of synchronization

Every object in Java can be used as a lock.

For synchronous methods, the lock is the current instance object.

For static synchronization methods, the lock is the class object of the current object.

For synchronized method blocks, locks are objects configured in synchronized parentheses.

When a thread attempts to access a synchronized code block, it must first get the lock and release the lock when exiting or throwing an exception. So where does the lock exist? What information will be stored in the lock?

4 principle of synchronization

The JVM specification stipulates that the JVM implements method synchronization and code block synchronization based on entering and exiting monitor objects, but the implementation details of the two are different. Code block synchronization is implemented using the monitorenter and monitorexit instructions, while method synchronization is implemented in another way. The details are not described in detail in the JVM specification, but method synchronization can also be implemented using these two instructions. The monitorenter instruction is inserted at the beginning of the synchronization code block after compilation, while monitorexit is inserted at the end of the method and at the exception. The JVM must ensure that each monitorenter must have a corresponding monitorexit paired with it. Any object has a monitor associated with it. When a monitor is held, it will be locked. When the thread executes the monitorenter instruction, it will try to obtain the ownership of the monitor corresponding to the object, that is, try to obtain the lock of the object.

4.1 Java object header

The lock is stored in the Java object header. If the object is of array type, the virtual machine stores the object header with 3 words (word width). If the object is of non array type, the object header is stored with 2 words. In a 32-bit virtual machine, one word width is equal to four bytes, that is, 32bit.

The hashcode, generation age and lock mark bit of the object are stored in mark word in the Java object header by default. The default storage structure of mark word of 32-bit JVM is as follows:

During operation, the data stored in mark word will change with the change of lock flag bit. Mark word may change to store the following four kinds of data:

Under the 64 bit virtual machine, mark word is 64bit in size, and its storage structure is as follows:

4.2 lock upgrade

JavaSE1. 6 in order to reduce the performance consumption caused by obtaining and releasing locks, the "biased lock" and "lightweight lock" are introduced, so in Java se 1 Six mile lock has four states: no lock state, biased lock state, lightweight lock state and heavyweight lock state. It will gradually upgrade with the competition. Locks can be upgraded but cannot be downgraded, which means that biased locks cannot be downgraded to biased locks after being upgraded to lightweight locks. The purpose of this lock upgrade but not downgrade strategy is to improve the efficiency of obtaining and releasing locks, which will be analyzed in detail below.

4.3 deflection lock

After previous studies, the author of hotspot found that in most cases, the lock not only does not exist multi-threaded competition, but is always obtained by the same thread many times. In order to make the thread obtain the lock at a lower cost, the biased lock is introduced. When a thread accesses the synchronization block and obtains the lock, it will store the lock biased thread ID in the lock record in the object header and stack frame. In the future, the thread does not need to spend CAS operation to lock and unlock when entering and exiting the synchronization block, but simply test whether the biased lock pointing to the current thread is stored in markword of the object header. If the test is successful, Indicates that the thread has obtained the lock. If the test fails, you need to test whether the bias lock ID in markword is set to 1 (indicating that it is currently a bias lock). If it is not set, use CAS to compete for the lock. If it is set, try to use CAS to point the bias lock of the object header to the current thread.

Revocation of biased lock: biased lock uses a mechanism to release the lock until competition occurs. Therefore, when other threads try to compete for biased lock, the thread holding biased lock will release the lock. Cancellation of bias lock, Need to wait for global security point (no bytecode is executing at this time point), it will first pause the thread with the biased lock, and then check whether the thread with the biased lock is alive. If the thread is not active, set the object header to the unlocked state. If the thread is still alive, the stack with the biased lock will be executed, and traverse the lock records of the biased object, the lock records in the stack and the pair The markword of the image header either re biases to other threads, or restores to no lock, or the marked object is not suitable for biased lock, and finally wakes up the suspended thread. Thread 1 in the following figure demonstrates the process of biased lock initialization, and thread 2 demonstrates the process of biased lock revocation.

Turn off bias lock: bias lock is enabled by default in Java 6 and Java 7, but it is activated only a few seconds after the application starts. If necessary, you can use the JVM parameter to turn off the delay - XX: biasedlockingstartupdelay = 0. If you determine that all locks in your application are in the contention state under normal circumstances, you can turn off the biased lock through the JVM parameter - XX: - usebiasedlocking = false, and it will enter the lightweight lock state by default.

4.4 lightweight lock

Lightweight lock locking: before the thread executes the synchronization block, the JVM will first create a space for storing lock records in the stack frame of the current thread, and copy the mark word in the object header into the lock record, officially known as displaced mark word. The thread then attempts to use CAS to replace the mark word in the object header with a pointer to the lock record. If it succeeds, the current thread obtains the lock. If it fails, it indicates that other threads compete for the lock. The current thread attempts to use spin to obtain the lock.

Lightweight lock unlocking: during lightweight unlocking, the atomic CAS operation will be used to replace the displaced mark word back to the object header. If it is successful, it indicates that no competition has occurred. If it fails, it indicates that there is competition in the current lock, and the lock will expand into a heavyweight lock. The following figure is a flowchart of lock inflation caused by two threads competing for locks at the same time.

Because spin consumes CPU, To avoid useless spin (for example, the thread that obtains the lock is blocked). Once the lock is upgraded to a heavyweight lock, it will not return to the lightweight lock state. When the lock is in this state, other threads will be blocked when trying to obtain the lock. When the thread holding the lock releases the lock, these threads will wake up, and the awakened thread will engage in a new round of lock contention.

5. Comparison of advantages and disadvantages of lock

6 reference source code

Some contents of this article refer to the hotspot source code. Object header source code markoop hpp。 Bias lock source code bias locking cpp。 And other source code objectmonitor CPP and basiclock cpp。

summary

The above is all about synchronized in Java concurrency. I hope it will be helpful to you. Interested friends can continue to refer to this website:

Java Web applications use stream limiting to handle a large number of concurrent requests

Implementation of BlockingQueue for Java Concurrent learning

Detailed explanation of high concurrency solution of Java System

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>