Comprehensive analysis of high-level core knowledge in Java-optimistic locking and pessimistic locking (what are pessimistic locking and optimistic locking? Two implementations of optimistic locking and its shortcomings, CAS algorithm)

1. What is pessimistic lock and optimistic lock

The optimistic lock corresponds to the optimistic people in life who always think about things going for the better, and the pessimistic lock corresponds to the pessimistic people in life who always think about things going for the bad. These two kinds of people have their own advantages and disadvantages, and one kind of person is better than the other depending on the scene.

1. What is pessimistic lock and optimistic lock

1) Pessimistic lock

Always assume the worst case. Every time you get the data, you think that others will modify it, so every time you get the data, you will lock it, so that others who want to get the data will block until it gets the lock ( shared resource It is only used by one thread at a time, other threads are blocked, and resources are transferred to other threads after use ). Many such locking mechanisms are used in traditional relational databases, such as row locks , table locks, etc., read locks , write locks, etc., all of which are locked before operations. Java, synchronizedand ReentrantLockrealization exclusive lock is pessimistic locking thought.

2) Optimistic lock

Always assume the best situation. Every time I get the data, I think that others will not modify it, so it will not be locked, but when updating, it will be judged whether others have updated the data during this period. You can use the version Number mechanism and CAS algorithm implementation. Optimistic locks are suitable for multi-read application types, which can improve throughput . Similar write_conditionmechanisms like those provided by databases are actually optimistic locks provided. In Java, java.util.concurrent.atomicthe atomic variable class under the package is implemented using CAS , an implementation of optimistic locking .

3) Use scenarios of two locks

From the above introduction of the two locks, we know that the two locks have their own advantages and disadvantages. One should not be considered as better than the other. For example, optimistic locks are suitable for less writes (read more scenarios) , that is, conflicts are true. When this happens rarely, this saves the overhead of the lock and increases the overall throughput of the system . However, if it is over-write, conflicts will usually occur frequently, which will cause the upper-level application to continue, which will retryreduce performance, so it is more appropriate to use pessimistic lock in the scenario of over-write .

Two, two common implementations of optimistic locking

Optimistic locking is generally implemented using the version number mechanism or CAS algorithm.

1. Version number mechanism

Generally, a data version number version field is added to the data table to indicate the number of times the data has been modified. When the data is modified, the version value will increase by one. When a thread A to update the data values will be read while reading data version value , at the time of submitting the update, if just to read the version value in the current database for the version value equal to only update, or retry Update operation until the update is successful.

Take a simple example:
suppose there is a version field in the account information table in the database , the current value is 1; and the current account balance field ( balance) is $100.

  1. Operator A reads it out ( version=1) at this time , and deducts $50 ($100-$50) from his account balance.
  2. During the operation of operator A, operator B also reads this user information ( version=1), and deducts $20 ( $100-$20) from his account balance .
  3. Operator A completes the modification work, adds one ( version=2) to the data version number balance=$50, and submits it to the database for update along with the account deduction balance ( ). At this time, because the submitted data version is greater than the current version of the database record , the data is updated, and the database record version is updated. Is 2.
  4. Operator B completed the operation and also added one to the version number ( version=2) to try to submit data to the database ( balance=$80), but at this time, when comparing the database record version, it was found that the data version number submitted by operator B was 2, and the current version of the database record was also It is 2, which does not meet the optimistic locking strategy of "The submitted version must be greater than the current version of the record to perform the update ". Therefore, the submission of Operator B is rejected.

In this way, it is avoided that the operator B version=1overwrites the operation result of the operator A with the result of the old data modification based on it.

2.CAS algorithm

Namely compare and swap (compare and swap) , is a well-known lock-free algorithm . Lock-free programming , that is, to achieve variable synchronization between multiple threads without using locks, that is, to achieve variable synchronization without threads being blocked, so it is also called non-blocking synchronization ( Non-blocking Synchronization). The CAS algorithm involves three operands

  • Need to read and write memory value V
  • The value to compare A
  • New value to be written B

If and only if the value of V is equal to A, CAS uses the new value B to update the value of V atomically, otherwise it will not perform any operation ( comparison and replacement is an atomic operation ). Under normal circumstances, it is a spin operation , that is, constant retry .

Three, the disadvantages of optimistic locking

ABA problem is a common problem with optimistic locking

1.ABA problem

If a variable V is the value of A when it is first read, and it is checked that it is still the value of A when it is ready to be assigned, can we show that its value has not been modified by other threads? Obviously it is not possible, because during this time its value may be changed to another value, and then changed back to A, the CAS operation will mistakenly believe that it has never been modified. This problem is called the "ABA" problem of CAS operation .

AtomicStampedReferenceClasses after JDK1.5 provide this ability. The compareAndSetmethod is to first check whether the current reference is equal to the expected reference and whether the current flag is equal to the expected flag. If all are equal, the reference and the value of the flag are atomically Set to the given update value.

2. Long cycle time and high overhead

Spin CAS (that is, it will execute in a loop until it is successful) if it is unsuccessful for a long time, it will bring a very large execution overhead to the CPU. If the JVM can support the pause instruction provided by the processor, the efficiency will be improved. The pauseinstruction has two functions. First, it can delay the execution of instructions in the pipeline ( de-pipeline), so that the CPU will not consume too much execution resources. The delay time depends on In the specific implementation version, the delay time is zero on some processors. It can avoid a second exit loop when the order due to memory conflicts ( memory order violation) causes CPU pipeline is cleared (CPU pipeline flush), thereby improving the efficiency of the CPU .

3. Only guarantee the atomic operation of a shared variable

CAS is only valid for a single shared variable . CAS is invalid when the operation involves multiple shared variables . But since JDK1.5 , it is provided AtomicReference类to ensure the atomicity between referenced objects. You can put multiple variables in one object to perform CAS operations . So we can use locks or AtomicReference类combine multiple shared variables into one Shared variables to operate.

Fourth, CAS and synchronized use scenarios

Simply put, CAS is suitable for less writes ( more read scenarios, generally less conflicts ), synchronized is suitable for more writes ( more write scenarios, generally more conflicts )

  1. In the case of less resource competition ( light thread conflicts ), the use of synchronized synchronization locks for thread blocking and wake-up switching, as well as switching operations between user mode and kernel mode wastes cpu resources; CAS is based on hardware and does not need to enter the kernel. There is no need to switch threads, and the chance of operating spin is less, so higher performance can be obtained.
  2. In the case of serious resource competition (serious thread conflict ), the probability of CAS spinning is relatively large, which wastes more CPU resources and is less efficient synchronized.

Supplement: The synchronized keyword in the field of Java concurrent programming has always been a veteran role. A long time ago, many people would call it a " heavyweight lock ". However, after JavaSE 1.6, it has been mainly included in order to reduce the performance consumption of acquiring and releasing locks, and the introduction of biased locks and lightweight locks, as well as various other optimizations, has become less important in some cases. . synchronizedThe underlying implementation of the main relies on the Lock-Free queue. The basic idea is to block after spin , and continue to compete for lock after competitive switching, which slightly sacrifices fairness, but achieves high throughput . In the case of fewer thread conflicts, performance similar to CAS can be obtained; and in the case of severe thread conflicts, the performance is much higher than CAS.

Comprehensive analysis of high-level core knowledge in Java-thread pool (benefits, Executor framework, ThreadPoolExecutor class brief introduction)
Comprehensive analysis of high-level core knowledge in Java-container (what is ArrayList? ArrayList core source code analysis, classic Demo)
Reference materials: "Java "Comprehensive analysis of intermediate and advanced core knowledge"
articles continue to update! Those who like it, remember to follow the blogger with one click and three consecutive times!

Guess you like

Origin blog.csdn.net/Java_Caiyo/article/details/110922705