[java] Locks in Java

foreword

1. Pessimistic lock

To give an example in life, suppose there is only one pit in the toilet, pessimistically locking the toilet will immediately lock the door, so that other people can only wait outside the door to go to the toilet. This state is "blocked".

I think that when I use data, there must be other threads to modify the data, so when I get the data, I will lock it first to ensure that the data will not be modified by other threads.

  • The synchronized keyword and the implementation class of Lock are both pessimistic locks

  • Applicable scenarios: Suitable for scenarios with many write operations, adding locks first can ensure that the data is correct during write operations.
    insert image description here

2. Optimistic lock

To give an example in life, assuming that there is only one pit in the toilet, Optimistic Lock thinks: In the wilderness, there are no people, no one will grab my pit, and it is a waste of time to close and lock the door every time, or not It's locked. You see, optimistic locks are inherently optimistic!

When you think you are using data 不会有别的线程修改数据或资源, you don't add locks.

In Java, it is implemented by using lock-free programming. It is only judged when updating data whether other threads have updated this data before.

If this data has not been updated, the current thread will successfully write the data it modified.
If the data has been updated by other threads, perform different operations according to different implementation methods, such as abandoning modification, retrying lock grabbing, etc.

  • Optimistic locking can be implemented using the version number mechanism and the CAS algorithm. The atomic classes under the java.util.concurrent.atomic package in the Java language are implemented using CAS optimistic locks.
  • Applicable scenarios: It is suitable for scenarios with many read operations. The feature of no lock can greatly improve the performance of read operations.
    insert image description here

3. Spin lock

principle

The principle of the 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 and suspending state. Just spin, and the lock can be acquired immediately after the thread holding the lock releases the lock, thus avoiding the consumption of user thread and kernel switching.

Thread spin needs to consume cup. If the lock cannot be obtained, the thread will occupy the CPU spin for a long time. You need to set a spin wait maximum event. If the lock is not obtained within the maximum wait time, the thread will stop spinning and enter the blocking state. .

Advantages and disadvantages of spin lock

advantage

Spin locks reduce thread blocking as much as possible, which can greatly improve the performance of code blocks that do not have intense competition for locks and occupy locks for a very short time, because the consumption of spin locks will be less than that of threads blocking, suspending, and then waking up The consumption of the operation (these operations will cause the thread to context switch twice)

shortcoming

The lock competition is fierce or the thread holding the lock needs to occupy the lock for a long time to execute the synchronization block. It is not suitable to use the spin lock, because the spin lock always occupies the CPU to do useless work before acquiring the lock, and there are a large number of threads 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, and other threads that need cups cannot obtain the cpu, resulting in a waste of cpu

Spinlock time threshold (1.6 introduced adaptive spinlock)

The purpose of the spin lock is to occupy the resources of the CPU without releasing it, and to process it immediately after the lock is acquired

If the spin execution time is too long, a large number of threads will be in the spin state and occupy CPU resources, which will affect the performance of the overall system

JVM's choice of spin period, the limit of jdk1.5 is hard-coded

Adaptive spin locks were introduced in 1.6. The spin time is not fixed, but is determined by the previous spin time on the same lock and the state of the lock owner. It is basically considered that the time for a thread context switch is best time

Turning on the spin lock

In JDK1.6, -XX:+UseSpinning is on; XX:PreBlockSpin=10 is the number of spins.
After JDK1.7, this parameter is removed and controlled by jvm

insert image description here

4. Reentrant lock (recursive lock)

Reentrant lock (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 in the JAVA environment Lock.

For Java ReentrantLock, his name can be seen as a reentrant lock. For Synchronized, it is also a reentrant lock.

敲黑板:可重入锁的一个好处是可一定程度避免死锁。

Taking synchronized as an example, look at the following code:
insert image description here

In the above code, methodA calls methodB. If a thread calling methodA has already acquired the lock and then calls methodB, there is no need to acquire the lock again. This is the characteristic of reentrant lock. If it is not a reentrant lock, mehtodB may not be executed by the current thread, which may cause a deadlock.
insert image description here

5. Read-write lock

In order to improve performance, Java provides read-write locks. Read locks are used for reading, and write locks are used for writing. If there is
no write lock, reading is non-blocking, which improves the performance of the program to a certain extent. effectiveness.

Read-write locks are divided into read locks and write locks. Multiple read locks are not mutually exclusive. The mutual exclusion of read locks and write locks is controlled by jvm. Programmers only need to install the corresponding locks and require codes to read only data. Many people can
simultaneously Read, but not write at the same time, you can use the read lock code to modify the data, only one person can write, and can not read at the same time, then write lock There is an interface for the read-write lock in Java, and there is also a specific java.util.concurrent.locks.ReadWriteLock implementation ReentrantReadWriteLock.
insert image description here

6. Fair lock

A fair lock means that multiple threads acquire locks in the order in which they apply for locks. This is similar to queuing up to buy tickets. Those who come first buy first, and those who come later line up at the end of the queue. This is fair.
insert image description here

First come, first served principle

Seven, unfair lock

Unfair locks mean that the order in which multiple threads acquire locks is not in the order in which they apply for locks. It is possible that threads that apply later acquire locks first than threads that apply first. In a high-concurrency environment, it may cause priority reversal or starvation state (a thread has not been locked)
insert image description here

Later ones may also acquire the lock first

The synchronized keyword in java is an unfair lock, and ReentrantLock is also an unfair lock by default.
insert image description here

Eight, shared lock

A shared lock means that a lock can be held by multiple threads. If a thread adds a shared lock to the data, then other threads can only add a shared lock to the data, not an exclusive lock. A thread that acquires a shared lock can only read data, but not modify it.

insert image description here

ReentrantReadWriteLock in JDK is a shared lock.

Nine, exclusive lock

An exclusive lock means that the lock can only be held by one thread at a time. If a thread adds an exclusive lock to the data, then other threads cannot add any type of lock to the data. A thread that acquires an exclusive lock can both read and modify data.
insert image description here

The implementation classes in the JDK synchronizedand java.util.concurrent(JUC)in the package Lockare exclusive locks.

10. Lightweight lock

When the thread competition becomes more intense, the biased lock will be upgraded to a lightweight lock. The lightweight lock believes that although the competition exists, the degree of competition is ideally low, and waits for the release of the previous thread by spinning. Lock.

Eleven, heavyweight lock

If the thread concurrency is further intensified, the spin of the thread exceeds a certain number of times, or a thread holds a lock, a thread is spinning, and a third thread accesses (in any case, the competition continues to increase), lightweight The lock will expand into a heavyweight lock, and the heavyweight lock will block all threads except the thread that owns the lock at this time.

Upgrading to a heavyweight lock is actually a mutual exclusion lock. If one thread gets the lock, the rest of the threads will be in a blocked waiting state.

In Java, the internal implementation principle of the synchronized keyword is the process of lock upgrade: no lock --> biased lock --> lightweight lock --> heavyweight lock.

This process will be introduced in detail when explaining the principle of the synchronized keyword later.

12. Bias lock

Java biased locking (Biased Locking) means that it will be biased towards the first thread to access the lock. If only one thread accesses the locked resource during operation and there is no multi-thread competition, then the thread does not need to be repeated. To acquire a lock, in this case, a bias lock will be added to the thread.

The implementation of the biased lock is realized by controlling the flag bit of the object Mark Word. If it is currently in a biased state, it is necessary to further judge whether the thread ID stored in the object header is consistent with the current thread ID, and if it is consistent, enter directly.

Thirteen, segment lock

Segment lock is a mechanism: The best example to illustrate segment lock is ConcurrentHashMap.

The principle of ConcurrentHashMap: It internally subdivides several small HashMaps, called segments (Segment). By default, a ConcurrentHashMap is further subdivided into 16 segments, which is the concurrency of locks. If you need to add a key-value to ConcurrentHashMap, instead of locking the entire HashMap, you first get the segment in which the key-value should be stored according to the hashcode, then lock the segment, and complete the put operation. In a multi-threaded environment, if multiple threads perform put operations at the same time, as long as the added key-value is not stored in the same segment, the threads can be truly parallel.

Thread safety: ConcurrentHashMap is a Segment array, and Segment is locked by inheriting ReentrantLock, so each operation that needs to be locked locks a segment, so as long as each Segment is thread-safe, global thread safe.

insert image description here

14. Mutex lock

A mutual exclusion lock is a conventional implementation of an exclusive lock, which means that only one visitor is allowed to access a certain resource at the same time, and it is unique and exclusive.

insert image description here

A mutex can only be owned by one thread at a time, and other threads can only wait.

15. Synchronization lock

A synchronization lock is synonymous with a mutex, which means that multiple threads are executed concurrently, and only one thread is allowed to access shared data at the same time.

Synchronization locks in Java: synchronized

Sixteen, deadlock

Deadlock is a phenomenon: if thread A holds resource x, thread B holds resource y, thread A waits for thread B to release resource y, thread B waits for thread A to release resource x, neither thread releases its own resources, the two threads cannot obtain each other's resources, which will cause a deadlock.

The deadlock in Java cannot be broken by itself, so after the thread is deadlocked, the thread cannot respond.

Therefore, we must pay attention to the concurrent scene of the program to avoid deadlock.

Seventeen, lock coarsening

Lock coarsening is to reduce the number of multiple synchronization blocks and expand the scope of a single synchronization block. In essence, it is to combine multiple lock and unlock requests into one synchronization request.

For example, there is a code synchronization block in a loop body, and the lock and unlock operation will be performed every loop.

insert image description here

After lock coarsening, it becomes like this:
insert image description here

Eighteen, lock elimination

Lock elimination means that the virtual machine compiler detects locks that share data without competition at runtime, and then eliminates these locks.
Give an example to make everyone understand better.
insert image description here

There is a test method in the above code, its main function is to concatenate string s1 and string s2.
The three variables s1, s2, and stringBuffer in the test method are all local variables. The local variables are on the stack, and the stack is private to the thread, so even if there are multiple threads accessing the test method, it is thread-safe.
We all know that StringBuffer is a thread-safe class, and the append method is a synchronization method, but the test method is inherently thread-safe. In order to improve efficiency, the virtual machine helps us eliminate these synchronization locks. This process is called lock elimination.
insert image description here

Nineteen, synchronized

Synchronized is a keyword in Java: used to modify methods and object instances. Belongs to exclusive locks, pessimistic locks, reentrant locks, and unfair locks.

  1. When acting on an instance method, what is locked is the instance of the object (this);

  2. When used as a static method, the Class class is locked, which is equivalent to a global lock of the class, and will lock all threads that call the method;

  3. When synchronized acts on a non-NULL object instance, all code blocks that lock the object are locked. It has multiple queues. When multiple threads access an object monitor together, the object monitor will store these threads in different containers.

Each object has a monitor object. Locking is to compete for monitor objects. Code block locking is realized by adding monitorenter and monitorexit instructions before and after the code block. Method locking is judged by a flag bit.

Twenty, the difference between Lock and synchronized

  • Lock: It is an interface in Java, reentrant lock, pessimistic lock, exclusive lock, mutex lock, synchronization lock.

    1. Lock needs to manually acquire and release locks. It's like the difference between automatic and manual

    2. Lock is an interface, and synchronized is a keyword in Java, and synchronized is a built-in language implementation.

    3. Synchronized will automatically release the lock held by the thread when an exception occurs, so it will not cause a deadlock phenomenon; while Lock, if an exception occurs, if it does not actively release the lock through unLock(), it is likely to cause a deadlock phenomenon, so When using Lock, you need to release the lock in the finally block.

    4. Lock can make the thread waiting for the lock respond to interruption, but synchronized cannot. When using synchronized, the waiting thread will wait forever and cannot respond to interruption.

    5. Through Lock, you can know whether the lock has been successfully acquired, but synchronized cannot.

    6. Lock can improve the efficiency of multiple threads for read operations by implementing read-write locks.

  • Advantages of synchronized:

    1. It is clear and simple enough, and when only basic synchronization functions are needed, use synchronized.

    2. Lock should ensure that the lock is released in the finally block. If you use synchronized, the JVM ensures that even if an exception occurs, the lock is automatically released.

    3. When using Lock, it is difficult for the Java virtual machine to know which lock objects are held by a specific thread lock.

21. The difference between ReentrantLock and synchronized

ReentrantLock is a class in Java: Inherited from the Lock class, reentrant lock, pessimistic lock, exclusive lock, mutex lock, synchronization lock.

  • focus

    • Same point:

      1. Mainly solve the problem of how to access shared variables safely

      2. All are reentrant locks, also known as recursive locks, the same thread can acquire the same lock multiple times,

      3. Guarantees the two characteristics of thread safety: visibility and atomicity.

  • difference:

    1. ReentrantLock is like a manual car, which needs to explicitly call the lock and unlock methods, and synchronized implicitly obtains the release lock.

    2. ReentrantLock can respond to interrupts, and synchronized cannot respond to interrupts. ReentrantLock provides more flexibility for dealing with lock unavailability

    3. ReentrantLock is API level, synchronized is JVM level

    4. ReentrantLock can implement fair locks and unfair locks. The default is unfair locks. synchronized is an unfair lock and cannot be changed.

    5. ReentrantLock can bind multiple conditions through Condition

Summarize

I talked about various locks in the Java language earlier, and finally summarized them through six questions:

insert image description here

Guess you like

Origin blog.csdn.net/u011397981/article/details/130346625