In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces the example analysis of lock mechanism in java, which is very detailed and has certain reference value. Friends who are interested must finish it!
What is synchronization? The JVM specification stipulates that JVM implements method synchronization and code block synchronization based on entering and exiting Monitor objects, but the implementation details are different. Code block synchronization is implemented using monitorenter and monitorexit instructions, while method synchronization is implemented in a different way, which is not detailed 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 synchronous code block after compilation, while the monitorexit is inserted at the end of the method and at the exception, and the JVM must have a corresponding monitorexit to match each monitorenter. Any object has a monitor associated with it, and when and a monitor is held, it will be locked. When the thread executes the monitorenter instruction, it will attempt to acquire the ownership of the monitor corresponding to the object, that is, to acquire the lock of the object.
Java object header
The lock is stored in the Java object header. If the object is an array type, the virtual machine stores the object header with 3 Word (word width), and if the object is a non-array type, the object header is stored with 2 word width. In a 32-bit virtual machine, one word width is equal to four bytes, or 32bit.
The Mark Word in the header of the Java object stores the object's HashCode, generational age, and lock marks by default. The default storage structure of Mark Word for 32-bit JVM is as follows:
During operation, the data stored in the Mark Word will change according to the change of the lock log bit. Mark Word may change to store the following four types of data:
Several types of locks
Thread blocking and awakening requires CPU to change from user mode to kernel state. Frequent blocking and awakening is a heavy task for CPU.
In order to reduce the performance consumption caused by acquiring and releasing locks, Java SE1.6 introduces "biased locks" and "lightweight locks", so there are four kinds of locks in Java SE1.6, namely, no lock state, partial lock state, lightweight lock state and heavyweight lock state, which will gradually upgrade with the competition. Locks can be upgraded but cannot be degraded, which means that biased locks cannot be degraded to biased locks after upgrading to lightweight locks. This lock upgrade strategy can not be degraded in order to improve the efficiency of acquiring and releasing locks.
Bias lock
In most cases, locks are not only not multithreaded, but are always acquired by the same thread multiple times. The purpose of the lock bias is to eliminate the CAS overhead of a thread after it has acquired the lock, seemingly giving the thread a bias. In addition, JVM also optimizes the situation where there will be multithreaded locks, but there is no lock competition, which sounds like a mouthful, but in real applications, this situation is indeed possible, because the thread may also have a synchronization relationship in addition to mutual exclusion, and the competition between the two threads being synchronized (one before and after) for shared object locks is likely to be non-conflicting. In this case, JVM uses an epoch to represent a lock-biased timestamp (actually generating a timestamp is quite expensive, so it should be understood here as a timestamp-like identifier)
Acquisition of biased lock
When a thread accesses the synchronous block and acquires the lock, the thread ID with lock bias is stored in the lock record in the object header and stack frame. Later, the thread does not need to spend CAS operation to lock and unlock when entering and exiting the synchronization block. Instead, simply test whether there is a bias lock pointing to the current thread in the Mark Word of the object header. If the test is successful, it indicates that the thread has acquired the lock. If the test fails, the thread has acquired the lock. You need to test again whether the identity of the biased lock in Mark Word is set to 1 (indicating that it is currently biased). If it is not set, the CAS contention lock is used. If so, try to use CAS to point the biased lock of the object header to the current thread.
Revocation of bias lock
The biased lock uses a mechanism that waits for competition to release the lock, so when other threads try to compete for the biased lock, the thread that holds the biased lock releases the lock. The revocation of the biased lock needs to wait for the global safe 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. If the thread is not active, the object header is set to unlocked. If the thread is still alive, the stack with the biased lock is executed, traversing the lock record of the biased object. The lock record in the stack and the Mark Word of the object header either re-favor other threads, or revert to no lock or mark the object is not suitable as a biased lock, and finally wake up the paused thread.
Bias lock setting
Turn off bias lock: bias lock is enabled by default in Java 6 and Java 7, but it is not activated until a few seconds after the application starts. If necessary, you can use the JVM parameter to turn off delay-XX:BiasedLockingStartupDelay = 0. If you are sure that all locks in your application are generally competitive, you can turn off the biased lock-XX:-UseBiasedLocking=false with the JVM parameter, and it will enter the lightweight lock state by default.
Spin lock
Thread blocking and awakening requires CPU to change from user mode to kernel state. Frequent blocking and awakening is a heavy task for CPU. At the same time, we can find that the locking state of many object locks only lasts for a short period of time, such as the self-adding operation of integers, it is obviously not worth blocking and waking up the thread in a very short time, so spin lock is introduced.
The so-called "spin" is to let the thread execute a meaningless loop, and then re-compete for the lock after the end of the loop. If the competition is not enough to continue the loop, the thread will always be in the running state during the cycle, but the JVM-based thread scheduling will give up the time slice, so other threads still have the opportunity to apply for the lock and release the lock.
The spin lock saves the time and space of the blocking lock (queue maintenance, etc.), but spinning for a long time becomes "busy waiting", which is obviously better than the blocking lock. Therefore, the number of spins is generally controlled within a range, such as 10100, etc., after which the spin lock will be upgraded to a blocking lock.
Lightweight lock
Add lock
Before the thread executes the synchronization block, JVM first creates a space to store the lock record in the stack frame of the current thread, and copies the Mark Word in the object header to 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 successful, the current thread acquires the lock, and if it fails, the spin acquires the lock. When the spin acquisition lock still fails, it indicates that there are other threads competing for the lock (two or more threads compete for the same lock). The lightweight lock expands into a heavy lock.
Unlock
When lightweight unlocking, the atomic CAS operation is used to replace the Displaced Mark Word back to the object header, which, if successful, indicates that the synchronization process is complete. If it fails, it indicates that another thread has tried to acquire the lock and wakes up the suspended thread while releasing the lock.
Weight lock
Weight lock in JVM, also known as object Monitor (Monitor), it is very similar to Mutex in C, in addition to having the function of Mutex (0 | 1) mutual exclusion, it is also responsible for realizing the function of Semaphore (semaphore), that is to say, it contains at least one competitive lock queue, and one signal blocking queue (wait queue). The former is responsible for mutex, and the latter is used for thread synchronization.
Comparison of advantages and disadvantages of locks
Reentrant lock
In this article, we are talking about reentrant locks in a broad sense, not just ReentrantLock under JAVA.
A reentrant lock, also known as a recursive lock, means that after the outer function of the same thread acquires the lock, the inner recursive function still has the code to acquire the lock, but it is not affected.
Both ReentrantLock and synchronized are reentrant locks in the JAVA environment.
Public class Test implements Runnable {
Public synchronized void get () {
System.out.println (Thread.currentThread () .getId ())
Set ()
}
Public synchronized void set () {
System.out.println (Thread.currentThread () .getId ())
}
@ Override
Public void run () {
Get ()
}
Public static void main (String [] args) {
Test ss=new Test ()
New Thread (ss) .start ()
New Thread (ss) .start ()
New Thread (ss) .start ()
}
}
The result is as follows, which is correct, that is, the same thread id is output twice in a row.
Threadid: 8
Threadid: 8
Threadid: 10
Threadid: 10
Threadid: 9
Threadid: 9
The greatest effect of reentrant locks is to avoid deadlocks.
Let's take spin lock as an example. (note: spin lock, that is, if you can't get the lock, you will keep checking the spin loop to wait, not to sleep in the kernel state, but to spin in the user state.)
Public class SpinLock {
Private AtomicReference owner = new AtomicReference ()
Public void lock () {
Thread current = Thread.currentThread ()
While (! owner.compareAndSet (null, current)) {
}
}
Public void unlock () {
Thread current = Thread.currentThread ()
Owner.compareAndSet (current, null)
}
}
The above is an implementation of spin lock.
For spin locks:
1. If there are two calls to lock () by the same thread, it will cause the second call to lock position to spin, resulting in a deadlock
Indicates that the lock is not reentrant. (within the lock function, verify that the thread is a thread that has acquired the lock.)
2. If problem 1 has been solved, the lock has been released when unlock () is called for the first time. The lock should not actually be released.
(count times for statistics)
After modification, it is as follows:
Public class SpinLock1 {
Private AtomicReference owner = new AtomicReference ()
Private int count = 0
Public void lock () {
Thread current = Thread.currentThread ()
If (current==owner.get ()) {
Count++
Return
}
While (! owner.compareAndSet (null, current)) {
}
}
Public void unlock () {
Thread current = Thread.currentThread ()
If (current==owner.get ()) {
If (countdown account 0) {
Count--
} else {
Owner.compareAndSet (current, null)
}
}
}
}
The spin lock implemented in this way is a reentrant lock.
Also, take a look at mutex:
Mutex can be divided into recursive lock (recursive mutex) and non-recursive lock (non-recursive mutex). Recursive locks can also be called reentrant locks (reentrant mutex)
Non-recursive lock is also called non-reentrant lock (non-reentrant mutex).
The only difference between the two is that the same thread can acquire the same recursive lock multiple times without creating a deadlock. If a thread acquires the same non-recursive lock multiple times, a deadlock occurs.
Mutex and Critical Section under Windows are recursive.
Pthread_mutex_t locks under Linux are non-recursive by default. Set the PTHREAD_MUTEX_RECURSIVE property that can be displayed, and set pthread_mutex_t as a recursive lock.
Fair lock
Queues for fair and unfair locks are based on a two-way linked list maintained within the lock, and the value of the table node Node is each thread requesting the current lock. The fair lock is that the value is taken from the head of the team each time.
The lock is implemented based on the following points:
The volatile keyword for the table node Node and status state.
Atomic operation of sum.misc.Unsafe.compareAndSet (see appendix).
Unfair lock
In the process of waiting for a lock, if any new thread tries to acquire the lock, there is a good chance that the lock will be acquired directly.
The above is all the contents of the article "example Analysis of locking Mechanism in java". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.