Java lock super detailed summary

table of Contents

 

1. JAVA lock

1.1. Optimistic locking

1.2. Pessimistic lock

1.3. Spin lock

1.4. Synchronized synchronization lock

1.5. ReentrantLock


 

 

1. JAVA lock

1.1. Optimistic lock

Optimistic locking is an optimistic idea, that is, it thinks that reads more and writes less, and the possibility of concurrent writes is low. Every time you get data, you think that others will not modify it, so it will not be locked, but it will be updated when updating. Judge whether someone else has updated the data during this period, read the current version number first when writing, and then lock the operation (compare the version number with the previous time, if the same, update), if it fails, repeat the read- Compare-write operation. Optimistic locking in java is basically realized through CAS operation. CAS is an update atomic operation. It compares whether the current value is the same as the incoming value, and if the same is the same, it is updated, otherwise it fails .

1.2. Pessimistic lock

Pessimistic locking is pessimistic thinking, that is, it is considered that there are too many writes, and the possibility of concurrent writing is high. Every time you get data, you think that others will modify it, so every time you read and write data, you will lock it, so other people think Reading and writing this data will block until the lock is obtained. The pessimistic lock in java is Synchronized , and the lock under the AQS framework first tries the cas optimistic lock to acquire the lock. If it is not acquired, it will be converted to a pessimistic lock, such as RetreenLock.

1.3. Spin lock

The principle of spin lock is very simple. If the thread holding the lock can release the lock resource in a short time, then those threads waiting for the competing lock do not need to switch between the kernel state and the user state to enter the blocking suspended state. Just wait (spin), and the lock can be acquired immediately after the thread holding the lock releases the lock, so as to avoid the consumption of switching between user threads and the kernel . Thread spin needs to consume the cup. To put it bluntly, the cup is doing useless work. If the lock cannot be obtained, the thread cannot always occupy the cup spin to do useless work, so you need to set a maximum time for spin waiting. If the execution time of the thread holding the lock exceeds the maximum time of spin waiting and the lock is not released, other threads competing for the lock will still not be able to acquire the lock within the maximum waiting time. At this time, the competing thread will stop spinning Enter the blocking state.
Advantages and disadvantages of spin locks
Spin locks reduce thread blocking as much as possible, which is not fierce for lock competition, and the performance of code blocks that occupy a very short lock time can be greatly improved, because the consumption of spin will be less than thread blocking, suspend and wake up The consumption of operations, these operations will cause the thread to have two context switches!
However, if the lock competition is fierce, or the thread holding the lock needs to occupy the lock to execute the synchronization block for a long time, it is not suitable to use the spin lock at this time, because the spin lock has always occupied the cpu for useless work before acquiring the lock. If XX is not XX, and a large number of threads are competing for a lock, it will take a long time to acquire the lock. The consumption of thread spinning is greater than the consumption of thread blocking and suspending operations. Other threads that need cups cannot obtain the cpu, resulting in cpu Waste. So in this case we have to close the spin lock;
Spinlock time threshold ( 1.6 introduces adaptive spinlock)
The purpose of the spin lock is to not release the resources occupying the CPU, and to wait until the lock is acquired to process it immediately. But how to choose the execution time of spin? If the spin execution time is too long, there will be a large number of threads in a spinning state occupying CPU resources, which will affect the overall system performance. Therefore, the choice of the spin period is extra important!
JVM's choice of spin period is hard-coded. The limit of jdk1.5 is hard-coded. In 1.6, an adaptive spin lock was introduced . Adaptive spin lock means that the time of spin is no longer fixed, but by The previous spin time on the same lock and the state of the lock owner are determined . Basically, it is considered that the time for a thread context switch is the best time. At the same time, the JVM has also done more for the current CPU load. Optimization. If the average load is less than CPUs, it will spin all the time. If more than (CPUs/2) threads are spinning, then the threads will block directly. If the spinning thread finds that the Owner has changed, the spin time will be delayed (spin If the CPU is in power-saving mode, it will stop spinning. The worst case of the spin time is the storage delay of the CPU (CPU A stores a data, and CPU B learns the direct time difference of this data), When spinning, the difference between thread priorities is appropriately discarded.
The opening of the spin lock
-XX:+UseSpinning is enabled in JDK1.6;
-XX:PreBlockSpin=10 is the number of spins;
After JDK1.7, remove this parameter and control by jvm;

1.4. Synchronized synchronization lock

synchronized It can treat any non-NULL object as a lock. He belongs to an exclusive pessimistic lock, but also a reentrant lock.
Synchronized scope
1. When acting on a method, the instance of the object (this) is locked;
2. When used as a static method, it is the Class instance that is locked, and because the relevant data of the Class is stored in the permanent zone PermGen (jdk1.8 is metaspace), the permanent zone is shared globally, so the static method lock is equivalent to the class A global lock of will lock all threads that call this method;
3. When synchronized acts on an object instance, all the code blocks that lock the object are locked. It has multiple queues. When multiple threads access an object monitor together, the object monitor stores these threads in different containers.
Synchronized core components
1) Wait Set: Which threads that are blocked by calling the wait method are placed here;
2) Contention List: competition queue , all threads requesting locks are first placed in this competition queue;
3) Entry List: The threads in the Contention List that are eligible to become candidate resources are moved to the Entry List ;
4) OnDeck: At any time, at most only one thread is competing for lock resources, and this thread is called OnDeck ;
5) Owner: The thread that currently has acquired the resource is called the Owner;
6) !Owner: The thread that currently releases the lock.
Synchronized implementation
1. JVM fetches a piece of data from the tail of the queue each time for lock contention candidates (OnDeck), but in the case of concurrency, ContentionList will be accessed by a large number of concurrent threads for CAS access. In order to reduce the contention for tail elements, JVM will partially The thread moves to EntryList as a candidate competing thread.
2. The Owner thread will migrate part of the threads in the ContentionList to the EntryList when unlocked, and designate a thread in the EntryList as the OnDeck thread (usually the most advanced thread).
3. The Owner thread does not directly pass the lock to the OnDeck thread, but passes the right of lock competition to OnDeck, and OnDeck needs to compete for the lock again. Although some fairness is sacrificed in this way, it can greatly improve the throughput of the system. In the JVM, this selection behavior is also called "competitive switching".
4. After the OnDeck thread acquires the lock resource, it becomes the Owner thread, and the one that does not get the lock resource still stays in the EntryList. If the Owner thread is blocked by the wait method, it will be transferred to the WaitSet queue until it is awakened by notify or notifyAll at some point, and it will re-enter the EntryList.
5. Threads in ContentionList, EntryList, WaitSet are in a blocked state, and the blocking is done by the operating system (implemented by the pthread_mutex_lock kernel function under the Linux kernel).
6. Synchronized is an unfair lock . Synchronized When the thread enters the ContentionList, the waiting thread will first try to spin to acquire the lock. If it cannot obtain it , it will enter the ContentionList . This is obviously unfair to the threads that have entered the queue. Another unfair thing is spin acquisition. The locked thread may also directly preempt the lock resource of the OnDeck thread.
7. Each object has a monitor object. Locking is competing for the monitor object . The locking of the code block is realized by adding monitorenter and monitorexit instructions before and after the lock. The method locking is judged by a flag bit.
8. Synchronization is a heavyweight operation that needs to call operating system-related interfaces , and its performance is inefficient. It may take more time to lock threads than useful operations.
9. Java 1.6, synchronized has carried out a lot of optimizations, including adaptive spin, lock elimination, lock coarsening, lightweight locks and bias locks, etc. , and the efficiency has been substantially improved. In the later Java1.7 and 1.8, the implementation mechanism of this keyword has been optimized. Introduced biased locks and lightweight locks . All have a mark bit in the object header and do not need to be locked by the operating system.
10. The lock can be upgraded from a biased lock to a lightweight lock and then to a heavyweight lock . This upgrade process is called lock expansion;
11. In JDK 1.6, biased locks and lightweight locks are turned on by default, and biased locks can be disabled through -XX:-UseBiasedLocking.

1.5. ReentrantLock

ReentantLock inherits the interface Lock and implements the methods defined in the interface. It is a reentrant lock. In addition to completing all the work that can be done by synchronized, it also provides functions such as responsive interrupt lock, pollable lock request, and timing Locks and other methods to avoid multi-threaded deadlock .
The main method of the Lock interface
1. void lock(): When this method is executed, if the lock is idle, the current thread will acquire the lock . On the contrary, if the lock is already held by other threads, the current thread will be disabled until the current thread acquires the lock.
2. boolean tryLock(): If the lock is available, the lock is acquired, and returns true immediately, otherwise it returns false . The difference between this method and lock() is that tryLock() just "attempts" to acquire the lock, if the lock is not available, it does not It will cause the current thread to be disabled, and the current thread will continue to execute code. The lock() method must acquire the lock. If the lock is not available, it will wait forever. The current thread does not continue to Execute it.
3. void unlock(): When this method is executed, the current thread will release the lock held . The lock can only be released by the holder. If the thread does not hold the lock, but executes the method, an exception may occur.
4. Condition newCondition(): Condition object, get notification component waiting . The component is bound to the current lock. The current thread can call the await() method of the component only after acquiring the lock. After the call, the current thread will scale the lock.
5. getHoldCount(): Query the number of times the current thread has held this lock, that is, the number of times this thread executes the lock method.
6. getQueueLength(): Returns the estimated number of threads waiting to acquire this lock. For example, if 10 threads are started and 1 thread acquires the lock, the return value is 9
7. getWaitQueueLength: (Condition condition) returns the estimated number of threads waiting for the given condition related to this lock. For example, 10 threads use the same condition object, and at this time these 10 threads have executed the await method of the condition object, then the execution of this method at this time returns 10
8. hasWaiters(Condition condition): Query whether there are threads waiting for a given condition (condition) related to this lock. For the specified contidion object, how many threads have executed the condition.await method
9. hasQueuedThread(Thread thread): Query whether a given thread is waiting to acquire this lock
10. hasQueuedThreads(): Are there threads waiting for this lock
11. isFair(): Whether the lock is a fair lock
12. isHeldByCurrentThread(): Whether the current thread keeps the lock locked, before and after the execution of the lock method of the thread are false and true respectively
13. isLock(): Whether this lock is occupied by any thread
14. lockInterruptibly(): If the current thread is not interrupted, acquire the lock
15. tryLock(): try to obtain the lock, only when the lock is not occupied by the thread when called, the lock is obtained
16. tryLock(long timeout TimeUnit unit): If the lock is not held by another thread within a given waiting time, acquire the lock.
Unfair lock
The mechanism of JVM assigning locks according to the principle of randomness and proximity is called unfair lock. ReentrantLock provides an initialization method for fair lock in the constructor, and the default is unfair lock. The actual execution efficiency of unfair locks far exceeds that of fair locks. Unless the program has special needs, the most commonly used unfair lock allocation mechanism.
Fair lock
Fair lock refers to that the lock allocation mechanism is fair. Usually the thread that first requests the lock will be allocated to the lock first. ReentrantLock provides the initialization method of fair lock in the constructor to define fair lock.
ReentrantLock synchronized
1. ReentrantLock uses the methods lock() and unlock() to perform locking and unlocking operations. Unlike synchronized, which is automatically unlocked by the JVM, ReentrantLock needs to be manually unlocked after being locked . In order to avoid abnormalities in the program and unable to unlock normally, ReentrantLock must be unlocked in the finally control block.
2. The advantages of ReentrantLock over synchronized are interruptible, fair lock, and multiple locks. In this case, ReentrantLock is required.
ReentrantLock implementation
public class MyService {
private Lock lock = new ReentrantLock();
//Lock lock=new ReentrantLock(true);//公平锁
//Lock lock=new ReentrantLock(false);//非公平锁
private Condition condition=lock.newCondition();//创建 Condition
public void testMethod() {
try {
lock.lock();//lock 加锁
//1:wait 方法等待:
//System.out.println("开始 wait");
condition.await();
//通过创建 Condition 对象来使线程 wait,必须先执行 lock.lock 方法获得锁
//:2:signal 方法唤醒
condition.signal();//condition 对象的 signal 方法可以唤醒 wait 线程
for (int i = 0; i < 5; i++) {
System.out.println("ThreadName=" + Thread.currentThread().getName()+ (" " + (i + 1)));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally13/04/2018
Page 68 of 283
{
lock.unlock();
}
}
}
The difference between the lock method of the Condition class and the Object class
1. The awiat method of the Condition class is equivalent to the wait method of the Object class
2. The signal method of the Condition class is equivalent to the notify method of the Object class
3. The signalAll method of the Condition class is equivalent to the notifyAll method of the Object class
4. The ReentrantLock class can wake up threads with specified conditions, while the wakeup of objects is random
The difference between tryLock and lock and lockInterruptibly
1. tryLock returns true if it can obtain the lock, false immediately if it can't, tryLock(long timeout, TimeUnit
unit), the time limit can be increased, if the lock is not obtained after this time period, return false
2. If lock can obtain the lock, it will return true.
3. lock and lockInterruptibly, if two threads execute these two methods separately, but interrupt these two threads at this time ,
lock will not throw an exception, while lockInterruptibly will throw an exception

Guess you like

Origin blog.csdn.net/qq_46914021/article/details/109185451