What are pessimistic locking and optimistic locking?

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 pessimists 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.

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., which are all locked before operations. Java, synchronizedand ReentrantLockrealization exclusive lock is pessimistic locking thought.

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, and the version can be used Number mechanism and CAS algorithm implementation. Optimistic locking is suitable for multi-read application types, which can improve throughput . The write_condition mechanism similar to the write_condition provided by the database is actually the optimistic lock provided. java.util.concurrent.atomicThe atomic variable class under the package in Java is implemented using CAS , an implementation of optimistic locking .

Use scenarios of two locks

From the above introduction of the two types of locks, we know that the two types of locks have their own advantages and disadvantages. One cannot 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 constantly retry, which will reduce the performance, so it is more appropriate to use pessimistic lock in the scenario of over-write.

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, which indicates the number of times the data has been modified. When the data is modified, the version value will increase by one. When thread A wants to update the data value, it will also read the version value while reading the data. When submitting the update, if the version value read just now is equal to the version value in the current database, it will update, otherwise try again Update operation until the update is successful.

Give a simple example:

Assuming that 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. When you need to update the account information table, you need to read the version field first.

  1. Operator A reads it out (version=1) 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 has completed the modification work. Before submitting the update, he will check whether the version of the database is consistent with the version read by himself. If they are the same, the data version number will be increased by 1 (version=2 ), together with the account deducted balance ( balance=$50), submitted to the database for update. 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 to 2.
  4. Operator B has completed the operation. Before submitting the update, he will check whether the version of the database is consistent with the version read by himself. However, when comparing the database record version at this time, he found that the version number of the data submitted by operator B is 2. The read version number is 1, which does not meet the optimistic locking strategy of "the last updated version is equal to the version number read by the operator for the first time". Therefore, the submission of operator B is rejected.

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

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
  • Value to be compared A
  • New value to be written B

If and only if the value of V is equal to A, CAS atomically updates the value of V with the new value B, 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 .

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 period its value may be changed to another value, and then changed back to A, then the CAS operation will mistakenly believe that it has never been modified. This problem is called the "ABA" problem of CAS operation  .

JDK 1.5 and later  AtomicStampedReference 类provide this ability, one of which  compareAndSet 方法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 value of the reference and the flag is set to Set 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, then the efficiency will be improved. The pause instruction has two functions. First, it can delay the de-pipeline execution of instructions, so that the CPU will not consume too much execution resources. The delay time depends on the specific implementation version, and the delay time is zero on some processors. Second, it can avoid the CPU pipeline flush caused by memory order violation when exiting the loop, thereby improving CPU execution efficiency.

3 Only the atomic operation of a shared variable can be guaranteed

CAS is only valid for a single shared variable. CAS is invalid when the operation involves multiple shared variables. But since JDK 1.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.

Use scenarios of CAS and synchronized

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 conflicts), the probability of CAS spinning is relatively large, which wastes more CPU resources and is less efficient than synchronized.

Supplement: The synchronized keyword in the field of concurrent programming in Java 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. . underlying synchronized implementation mainly depends  Lock-Free  queue, the basic idea is  the spin obstruction , the competition to continue to compete lock switch , a little at the expense of fairness, but to obtain 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.

Guess you like

Origin blog.csdn.net/sanmi8276/article/details/108580488