preface

Learned about transaction isolation levels and concurrency mechanisms (row locking, table locking, pessimistic locking…) when studying databases. After learning Java multithreading, it increased to 8 locks (spin, pessimism, ReentantLock, synchronized…). I got confused for a while. This article will not do a deep discussion of a point, just do an outline of the summary, specific details of operation to refer to other information 😑


1. Lock the database

Database locks are for transactions. Of course, transactions and multithreading seem to have some relationship. They both represent the execution of an instruction.


1.1 pessimistic locks

When we want to change a piece of data in a database, in order to avoid other people to change at the same time, the best way is to directly lock the data to prevent concurrency. Pessimistic locking is called because it is a form of concurrency control that takes a pessimistic view of data changes. We generally believe that the probability of data being changed concurrently is relatively high, so we need to lock the data before the change.

implementation

S lock (read lock, shared lock)

When transaction A reads data Y, transaction A locks transaction S to prevent transaction B from writing data Y to transaction A, causing inconsistency between transaction A’s two reads of data Y


X lock (write lock, exclusive lock)

When transaction A writes data Y, transaction A locks transaction X to prevent transaction B from reading data Y because transaction B is likely to read temporary dirty data


1.2 optimistic locking

In contrast to pessimistic locks, optimistic locks do not use the locking mechanism provided by the database when the database is being processed. A common way to implement optimistic locking is to record data versions. Optimistic concurrency control believes that the probability of a data race between transactions is low, so it goes as direct as possible, locking until commit time, so no locks or deadlocks are generated.


implementation

Optimistic locking eliminates the need for database locking mechanisms. A typical implementation method is Compare and Swap(CAS) technology. When multiple threads try to update the same variable at the same time using CAS, only one of them can update the value of the variable while the others fail. The failed thread is not suspended, but is told that it failed in the race and can try again. The disadvantage is the existence of ABA problems.


1.3 intention to lock

InnoDB also has two internal Intention Locks, both table Locks, in order to allow both row Locks and table Locks to coexist and implement a multi-grained locking mechanism.

  • Intended Shared Lock (IS)

    Indicates that a transaction IS going to add a shared lock to a row. The transaction must acquire the IS lock of the table before adding a shared lock to the row.

  • Intended Exclusive lock (IX)

    Indicates that a transaction is going to add an exclusive lock to a row. The transaction must acquire the IX lock of the table before adding an exclusive lock to the row.


1.4 Row lock table lock page lock

In terms of lock granularity, the MySQL database can have table level, page level, and row level locks depending on the storage engine.


Table locks

MySQL lock is a lock with the largest granularity. It locks the entire table of the current operation. It is simple to implement, consumes less resources, and locks quickly without deadlock. It has the highest lock granularity, the higher the probability of triggering lock conflicts, and the lowest concurrency. Both MyISAM and InnoDB engines support table-level locking.


Row locks

The lock is the least granular lock in Mysql, and only locks the row on which the current operation is performed. Row-level locking can greatly reduce the conflict of database operations. The locking granularity is the smallest, the concurrency is high, but the locking overhead is the largest, the locking is slow, and the deadlock may occur. Although the use of row-level locking is characterized by small granularity and high concurrency, table-level locking is also necessary in some scenarios.

  • When a transaction updates most data in a large table, it is more efficient to directly use table-level locking and avoid frequent row-level locking.
  • Transactions are complex and the use of row-level locking is likely to result in deadlocks leading to rollback.


Page locks

Page level locking is a unique level of locking in MySQL and is not very common in other database management software. Page level locking is characterized by locking granularity that falls between row level locking and table level locking, so the resource overhead required to acquire a lock and the concurrent processing power it provides also fall between the two. In addition, deadlocks can occur with page-level locking just as they do with row-level locking.


1.5 lock algorithm

Record Lock

Record lock, which locks a row record

Gap Lock

Gap lock, lock an interval

Next-Key Lock

Record lock + gap lock to lock row records and intervals



Java multithreaded 8 locks


2.1 Fair lock/Non-Fair Lock

  1. A fair lock is one in which multiple threads acquire a lock in the order in which they apply for it. (First come, first served, very fair)
  2. An unfair lock means that multiple threads acquire a lock in an order other than that in which they apply for the lock. It is possible that the thread that applies for the lock later takes precedence over the thread that applies for the lock first. It could be, like, a priority reversal or starvation.




2.2 Reentrant lock

A reentrant lock, also known as a recursive lock, is a lock that is automatically acquired by the inner method while the outer method is acquired by the same thread. To be a little abstract, here’s an example of the code. In the case of Synchronized, it is also a reentrant lock. One of the benefits of reentrant locking is that deadlocks are somewhat avoided.

synchronized void setA(a) throws Exception{

    Thread.sleep(1000);

    setB();

}

synchronized void setB(a) throws Exception{

    Thread.sleep(1000);

}

/ /.......................................... Call setA ()...............................................................
// Both methods lock this object. If synchronized is not reentrant (a thread can lock multiple times), then setB() will not lock this, and the thread will be stuck at setA().Copy the code


2.3 Exclusive/Shared Locks

  1. An exclusive lock means that the lock can only be held by one thread at a time.
  2. A shared lock means that the lock can be held by multiple threads.

For Java ReentrantLock, it is an exclusive lock. But for ReadWriteLock, another class that implements Lock, the read Lock is a shared Lock and the write Lock is an exclusive Lock. Read locks are shared to ensure that concurrent reads are highly efficient. Read/write, read/write, and write/write are mutually exclusive. Exclusive locks and shared locks are also implemented through AQS, through the implementation of different methods, to achieve exclusive or shared. Synchronized, of course.


2.4 the mutex/Read-write lock

The exclusive/shared locks mentioned above are a broad term, and the mutex/read-write locks are a concrete implementation. The Java implementation of the mutex is called ReentrantLock. The Java implementation of the read/write lock is called ReadWriteLock



2.5 optimistic locking/Pessimistic locking


  1. Pessimistic locking considers that concurrent operations on the same data must be modified, even if no modification is made. Therefore, pessimistic locking takes the form of locking for concurrent operations on the same data. The pessimistic view is that concurrent operations without locks are bound to cause problems.
  2. Optimistic locking assumes that concurrent operations on the same data will not be modified. When updating the data, the data will be updated by trying to update and constantly re-updating. Optimistically, concurrent operations without locks are fine.

Implementation:

  1. The use of pessimistic locking in Java is the use of various locks.
  2. The use of optimistic locking in Java is lockless programming, often using the CAS algorithm, a typical example is the atomic class, CAS spin to achieve atomic operation updates.



Section 2.6 the lock

Segment lock is actually a lock design, not a specific lock, for ConcurrentHashMap, its concurrent implementation is to achieve efficient concurrent operations through the form of segment lock. ConcurrentHashMap uses segmental locking internally. The piecewise lock is designed to refine the granularity of the lock by locking only one item in the array without updating the entire array.



2.7 Biased locking/lightweight locking/heavyweight locking

These three types of locks refer to the state of the lock, and are Synchronized. Java 5 introduced a lock escalation mechanism to implement Synchronized efficiently. The state of these three locks is indicated by the fields in the object header of the object monitor.


  1. Biased locking is when a synchronized piece of code is accessed by a thread all the time, so that thread will automatically acquire the lock. Reduces the cost of acquiring locks.
  2. A lightweight lock means that when a biased lock is accessed by another thread, the biased lock is upgraded to a lightweight lock, and the other threads spin to try to acquire the lock without blocking and improve performance.
  3. When the lock is a lightweight lock, the other thread spins, but the spin does not last forever. When the thread spins a certain number of times and has not acquired the lock, it will enter the block, and the lock will expand to a heavyweight lock. Heavy locking causes other requesting threads to block, causing performance degradation.

From bias lock -> lightweight lock -> heavyweight lock is the lock upgrade process, the process is not reversible



2.8 the spin lock

In Java, spin locking means that the thread trying to acquire the lock does not block immediately, but tries to acquire the lock in a circular manner. This has the advantage of reducing the cost of thread context switching, but the disadvantage is that the loop consumes CPU.