Java Concurrent Programming (05): pessimistic lock and optimistic lock mechanism

Source code of this article: GitHub · click here | gitee · click here

1、 Resources and locking

1. Scene description

Multithreading accesses the same resource concurrently. If thread a obtains the variable and modifies the variable value, thread C also obtains the variable value and modifies it at this time. Two threads process a variable concurrently, which will lead to concurrency problems.

This parallel processing of database is very common in actual business development. Two threads modify the database values successively, resulting in data problems. The probability of recurrence of the problem is small. When processing, it is necessary to have a concept of the whole module system in order to easily locate the problem.

2. Demonstration case

public class LockThread01 {
    public static void main(String[] args) {
        CountAdd countAdd = new CountAdd() ;
        AddThread01 addThread01 = new AddThread01(countAdd) ;
        addThread01.start();
        AddThread02 varThread02 = new AddThread02(countAdd) ;
        varThread02.start();
    }
}
class AddThread01 extends Thread {
    private CountAdd countAdd  ;
    public AddThread01 (CountAdd countAdd){
        this.countAdd = countAdd ;
    }
    @Override
    public void run() {
        countAdd.countAdd(30);
    }
}
class AddThread02 extends Thread {
    private CountAdd countAdd  ;
    public AddThread02 (CountAdd countAdd){
        this.countAdd = countAdd ;
    }
    @Override
    public void run() {
        countAdd.countAdd(10);
    }
}
class CountAdd {
    private Integer count = 0 ;
    public void countAdd (Integer num){
        try {
            if (num == 30){
                count = count + 50 ;
                Thread.sleep(3000);
            } else {
                count = count + num ;
            }
            System.out.println("num="+num+";count="+count);
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}

This case demonstrates that multithreading modifies the count value concurrently, resulting in inconsistent results with expectations. This is the most common problem under multithreading concurrency, especially when updating data concurrently.

When concurrency occurs, it is necessary to control the accuracy of data reading and writing in concurrency through certain methods or strategies. This is called concurrency control. There are many means to realize concurrency control. The most common way is to lock resources. There is also a simple implementation strategy: read data before modifying data and add restrictions when modifying data, Ensure that the modified content has not been modified during this period.

2、 Introduction to the concept of lock

1. Introduction to locking mechanism

One of the most critical problems in concurrent programming is that multithreading processes the same resource concurrently to prevent the conflict of resource use. A key solution is to lock the resources: multi line programming access. Lock is used to control the way that multiple threads access shared resources. The lock mechanism can enable shared resources to be accessed by only one thread task at any given time, so as to realize the synchronization and mutual exclusion of thread tasks. This is the most ideal but the worst performance way. The shared read lock mechanism allows multiple tasks to access resources concurrently.

2. Pessimistic lock

Pessimistic locking always assumes that the data read each time will be modified, so it is necessary to lock the read data. It has strong resource exclusivity and exclusivity. In the whole data processing process, the data is locked. For example, the implementation of synchronized keyword is a pessimistic mechanism.

The implementation of pessimistic lock often depends on the locking mechanism provided by the database. Only the locking mechanism provided by the database layer can truly ensure the exclusivity of data access. Otherwise, even if the locking mechanism is implemented in this system, it can not ensure that the external system will not modify the data. Pessimistic lock is mainly divided into shared read lock and exclusive write lock.

Basic mechanism of exclusive lock: also known as write lock, it allows transactions that obtain exclusive locks to update data, and prevents other transactions from obtaining shared read locks and exclusive locks of the same resources. If transaction t applies a write lock to data object a, transaction t can read a or modify A. other transactions cannot apply any lock to a until t releases the write lock on a.

3. Optimistic lock

Compared with pessimistic lock, optimistic lock adopts a more relaxed locking mechanism. In most cases, pessimistic locking depends on the locking mechanism of the database to ensure the maximum exclusivity of the operation. However, there is a large amount of overhead of database performance, especially for long transactions, which accounts for a lot of resources. The optimistic locking mechanism solves this problem to a certain extent.

Optimistic locking is mostly implemented based on the data version recording mechanism, which adds a version ID to the data. In the database table based version solution, it is generally realized by adding a version field to the database table. When reading out the data, read out this version number together. When updating later, add one to this version number. At this time, compare the version data of the submitted data with the current version information of the corresponding record of the database table. If the version number of the submitted data is equal to the current version number of the database table, it will be updated, otherwise it will be considered as expired data. Optimistic locking mechanism may lead to a large number of update failed operations in high concurrency scenarios.

The implementation of optimistic lock is a policy level implementation: CAS (compare and swap). When multiple threads try to use CAS to update the same variable at the same time, only one thread can successfully update the value of the variable, while other threads fail. The failed thread will not be suspended, but will be told that it has failed in the competition and can try again.

4. Mechanism comparison

The implementation mechanism of pessimistic lock itself is at the cost of performance loss. Multi thread contention, locking and releasing lock will lead to more context switching and scheduling delay. The locking mechanism will generate additional overhead, increase the probability of deadlock and cause performance problems.

Although the optimistic lock will judge whether the updated data has changed based on the comparison detection method, it is uncertain whether the data has changed. For example, the data read by thread 1 is A1, but the value of thread 2 operation A1 changes to A2, and then changes to A1 again, so that the task of thread 1 is not perceived.

Pessimistic lock locks every data modification, which is inefficient and has a low probability of data writing failure. It is more suitable for the scenario of writing more and reading less.

Optimistic lock is not really locked. It has high efficiency, high probability of failure in writing data, and is prone to business exceptions. It is more suitable for the scenario of reading more and writing less.

Whether to sacrifice performance or pursue efficiency depends on the business scenario. This choice depends on empirical judgment. However, with the technical iteration, the improvement of database efficiency and the emergence of cluster mode, performance and efficiency can be achieved.

3、 Lock foundation case

1. Lock method description

Lock: execute a lock acquisition and return immediately after acquisition;

Lock interruptible: it can be interrupted during lock acquisition;

Trylock: when trying to acquire a lock without blocking, you can set the timeout. If the acquisition is successful, it returns true, which is conducive to thread status monitoring;

Unlock: release the lock and clear the thread status;

Newcondition: get the waiting notification component and bind it to the current lock;

2. Application case

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.reentrantlock;
public class LockThread02 {
    public static void main(String[] args) {
        LockNum lockNum = new LockNum() ;
        LockThread lockThread1 = new LockThread(lockNum,"TH1");
        LockThread lockThread2 = new LockThread(lockNum,"TH2");
        LockThread lockThread3 = new LockThread(lockNum,"TH3");
        lockThread1.start();
        lockThread2.start();
        lockThread3.start();
    }
}
class LockNum {
    private Lock lock = new reentrantlock() ;
    public void getNum (){
        lock.lock();
        try {
            for (int i = 0 ; i < 3 ; i++){
                System.out.println("ThreadName:"+Thread.currentThread().getName()+";i="+i);
            }
        } finally {
            lock.unlock();
        }
    }
}
class LockThread extends Thread {
    private LockNum lockNum ;
    public LockThread (LockNum lockNum,String name){
        this.lockNum = lockNum ;
        super.setName(name);
    }
    @Override
    public void run() {
        lockNum.getNum();
    }
}

Here, multithreading executes tasks in turn based on the lock mechanism. This is the basic usage of lock and the detailed explanation of various APIs. I'll talk about it next time.

3. Compared with synchronized

The lock mechanism based on synchronized implementation has high security, but once the thread fails, an exception is thrown directly, and there is no chance to clean up the thread state. By explicitly using lock syntax, you can finally release the lock in the finally statement and maintain a relatively normal thread state. In the process of obtaining the lock, you can try to obtain it or try to obtain it for a period of time.

4、 Source code address

GitHub·地址
https://github.com/cicadasmile/java-base-parent
GitEE·地址
https://gitee.com/cicadasmile/java-base-parent

Recommended reading: Java Foundation Series

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>