1. Fair lock/Non-fair lock
1.1 Overview of Fair Locking
Fairness is in terms of lock acquisition. If a lock is fair, then the lock acquisition order should correspond to the absolute time order of the request. By default, both ReentrantLock and ReadWriteLock are in non-fair mode. The efficiency of non-fair lock is higher than that of fair lock (no wasteful thread switching).
1.2 Self-write fair lock
FairLock,QueueObject
import java.util.ArrayList; import java.util.List; / / the class without the reentrant function. / / https://gitee.com/zgy/codes/7seiqx2nwuo4dhrj8pf6m33 there is a fair lock code public class FairLock {private Boolean isLocked = false; private Thread lockingThread = null; Private List<QueueObject> waitingThreads = new ArrayList<QueueObject>(); Public void lock() throws InterruptedException {void lock() throws InterruptedException { QueueObject queueObject = new QueueObject(); synchronized (this) { waitingThreads.add(queueObject); } try { queueObject.doWait(); } catch (InterruptedException e) { synchronized (this) { waitingThreads.remove(queueObject); } throw e; }} donotify public synchronized void unlock() {if (this.lockingThread! = Thread.currentThread()) { throw new IllegalMonitorStateException("Calling thread has not locked this lock"); } isLocked = false; lockingThread = null; if (waitingThreads.size() > 0) { waitingThreads.get(0).doNotify(); }}} public class QueueObject {private Boolean isNotified = false; Public synchronized void doWait() throws InterruptedException {// synchronized void doWait() throws InterruptedException. isNotified) { this.wait(); } this.isNotified = false; } public synchronized void doNotify() { this.isNotified = true; this.notify(); } public boolean equals(Object o) { return this == o; }}Copy the code
1.3 Fair locks and Non-fair locks in ReentrantLock
ReentrantLock.FairSync ReentrantLock.FairSync
package java.util.concurrent.locks; public class ReentrantLock implements Lock, java.io.Serializable { //1.Sync abstract static class Sync extends AbstractQueuedSynchronizer { final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } //2.FairSync extends Sync {// tryAcquire protected final Boolean tryAcquire(int) acquires) { final Thread current = Thread.currentThread(); int c = getState(); If (c == 0) {return true if (c == 0) {return false if (c == 0) {return true if (c == 0) {return false if (c == 0); hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } //3. NonfairSync static final class NonfairSync extends Sync { private static final long serialVersionUID = 7316153563782823691L; final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }}}Copy the code
1.4 ReentrantReadWriteLock Also has fair locks and non-fair locks.
package java.util.concurrent.locks; public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { abstract static class Sync extends AbstractQueuedSynchronizer { } static final class FairSync extends Sync { private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock() { return hasQueuedPredecessors(); } final boolean readerShouldBlock() { return hasQueuedPredecessors(); } } static final class NonfairSync extends Sync { private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() { return false; // writers can always barge } final boolean readerShouldBlock() { return apparentlyFirstQueuedIsExclusive(); }}}Copy the code
2. Exclusive locks and shared locks
2.1 an overview of the
- Exclusive lock
Exclusive locks, also known as exclusive locks, can be held by only one thread at a time. Other threads must wait for the lock to be released before they can acquire it. (Atomicity, which excludes other threads from entering.)
- A Shared lock
Shared locks allow multiple threads to acquire a lock at the same time, a lock can be owned by multiple threads at the same time. (Can be accessed by multiple threads simultaneously)
For example, 2.2
- ReentrantLock is an exclusive lock. CountDownLatch is a shared lock. Both classes are simple, that is, either exclusive locks or shared locks.
- ReentrantReadWriteLock is a lock that contains both exclusive locks and shared locks. The following uses ReentrantReadWriteLock as an example. When we use the ReentrantReadWriteLock write lock, we use the exclusive lock feature. ReentrantReadWriteLock uses the shared lock feature when you use read locks.
3. Read and write locks
3.1 Overview of Read/write Locking
Contains both exclusive locks and shared locks. Write locks are exclusive locks and read locks are shared locks.
- Read: Multiple threads can enter, ensuring that read performance is improved, threads are not mutually exclusive wait
- Read/write: Threads are mutually exclusive and wait. Multiple reads can be performed simultaneously as long as no other operations can be performed while writing.
- Write: Threads are mutually exclusive and wait
ReentrantReadWriteLock also uses fair and non-fair locks.
3.2 the sample
import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class MyReadWriteLock { private Map<String, Object> map = new HashMap<>(); private ReadWriteLock rwl = new ReentrantReadWriteLock(); private Lock r = rwl.readLock(); private Lock w = rwl.writeLock(); public Object get(String key) { r.lock(); System.out.println(thread.currentThread ().getName() + "Read operation is executing.." ); try { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return map.get(key); } finally { r.unlock(); System.out.println(thread.currentThread ().getName() + "Read finish.." ); } } public void put(String key, Object value) { w.lock(); System.out.println(thread.currentThread ().getName() + "Write operation is executing.." ); try { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } map.put(key, value); } finally { w.unlock(); System.out.println(thread.currentThread ().getName() + "Write completed.." ); } } } ublic class MyReadWriteLockTest { public static void main(String[] args) { writeWrite(); writeRead(); readRead(); } /** Thread-0: = "Thread-0"; Thread-0 The write operation is complete.. Thread-2 The write operation is executing.. Thread-2 The write operation is complete.. Thread-1 write operation is executing.. Thread-1 The write operation is complete.. */ public static void writeWrite() { MyReadWriteLock myReadWriteLock1 = new MyReadWriteLock(); new Thread(new Runnable() { @Override public void run() { myReadWriteLock1.put("key1", "value1"); } }).start(); new Thread(new Runnable() { @Override public void run() { myReadWriteLock1.put("key2", "value2"); } }).start(); new Thread(new Runnable() { @Override public void run() { myReadWriteLock1.put("key3", "value3"); } }).start(); } /** * main write operation is executing.. Main The write operation is complete.. Thread-0 read operation is executing.. The read operation of thread-0 is completed.. Thread-2 The write operation is executing.. Thread-0->value1 thread-2 The write operation is complete.. Thread-1 Read operation is executing.. Thread-3 The read operation is executing.. Thread-3 The read operation is complete.. The read operation of thread-1 is complete.. Public static void writeRead() {MyReadWriteLock;} public static void writeRead() {MyReadWriteLock myReadWriteLock2 = new MyReadWriteLock(); myReadWriteLock2.put("key1", "value1"); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock2.get("key1")); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock2.get("key1")); } }).start(); new Thread(new Runnable() { @Override public void run() { myReadWriteLock2.put("key1", "value2"); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock2.get("key1")); } }).start(); } public static void readRead() {MyReadWriteLock myReadWriteLock3 = new MyReadWriteLock(); myReadWriteLock3.put("key1", "value1"); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"->"+myReadWriteLock3.get("key1")); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(myReadWriteLock3.get("key1")); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(myReadWriteLock3.get("key1")); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(myReadWriteLock3.get("key1")); } }).start(); new Thread(new Runnable() { @Override public void run() { System.out.println(myReadWriteLock3.get("key1")); } }).start(); }}Copy the code
4.ReentrantReadWriteLock source code parsing
4.1 an overview of the
- Read/write the state that the lock needs to hold
-
- Number of write lock reentries
-
- Number of read locks
-
- The number of reentries per read lock
1111 1111 1111-1111 1111 1111 1111 1111 1111
- The first 16 bits (high) store the number of read locks, and the last 16 bits (low) store the number of write locks
The int value represents the number of reentrants
4.2 Core source code
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { //1. Private readerLock and writerLock, through the following writeLock () and readLock () to access the private final ReentrantReadWriteLock. ReadLock readerLock; private final ReentrantReadWriteLock.WriteLock writerLock; final Sync sync; Public ReentrantReadWriteLock() {this(false); } sync public ReentrantReadWriteLock(Boolean fair) {sync = fair? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } / / through the public methods to access writeLock and readerLock public ReentrantReadWriteLock. WriteLock writeLock () {return writerLock; } public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } public static class implements Lock; public static class implements Lock; public static class implements Lock; java.io.Serializable { private static final long serialVersionUID = -5992448646407690164L; private final Sync sync; Sync protected ReadLock(ReentrantReadWriteLock lock) {sync = lock.sync; } public void lock() {sync.acquireshared (1); Public static class WriteLock implements Lock; //3. Public static class WriteLock implements Lock; java.io.Serializable { private static final long serialVersionUID = -4992448646407690164L; private final Sync sync; protected WriteLock(ReentrantReadWriteLock lock) { sync = lock.sync; Public void lock() {sync.acquire(1); public void lock() {sync.acquire(1); }} / / Sync inner class implementation class AQS abstract static class Sync extends AbstractQueuedSynchronizer {/ * SHARED_SHIFT - > 16 SHARED_UNIT->65536 MAX_COUNT->65535 EXCLUSIVE_MASK->65535 int maximum value :-2147483648 to 2147483648 Int unsigned 0~4,294,967,296(2^32), split into 2 parts maximum: 65536(2^16)(65536*65536=4,294,967,296) 1111 1111 1111 1111-1111 1111 1111 1111 1111 */ static final int SHARED_SHIFT = 16; static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 << SHARED_SHIFT); static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | return c >>> SHARED_SHIFT; } /** Returns the number of exclusive holds represented in count */ // static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; Protected final Boolean tryRelease(int releases) {} {} / / access to a Shared lock, it must first determine whether read lock, then whether the thread, then the other threads, Protected final int tryAcquireShared(int unused) { TryReleaseShared (int unused) {}} static final class FairSync extends Sync {private static final long serialVersionUID = -2274990926593161451L; final boolean writerShouldBlock() { return hasQueuedPredecessors(); } final boolean readerShouldBlock() { return hasQueuedPredecessors(); }} static final class NonfairSync extends Sync {private static final Long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() { return false; // writers can always barge } final boolean readerShouldBlock() { return apparentlyFirstQueuedIsExclusive(); }}}Copy the code
4.3 Core Summary:
- 1. WriteLock and ReadLock, use the Sync synchronizer, Sync AbstractQueuedSynchronizer inheritance, also have fair and unfair
- 2.WriteLock calls Sync exclusive lock tryAcquire,ReadLock calls Sync shared lock tryAcquireShared, and both record the number of reentrings
- 3.private volatile int state; The first 16 (high) bits of state save the number of read lock reentries (65536), and the last 16 (low) bits save the number of write lock reentries (65536).
- 4. There are operations in which an inner class calls properties of an outer class.
5. ReentrantReadWriteLock Lock degradation
5.1 an overview of the
-
Lock degradation means that a write lock is degraded to a read lock. Lock degradation refers to the degradation of a write lock to a read lock. Lock degradation is the process of holding on to a write lock, acquiring a read lock, and then releasing the write lock
-
Lock Upgrade ReentrantReadWriteLock Does not support lock upgrade
Upgrade a read lock to a write lock. When the read lock is not released, the write lock is acquired and the read lock is released
5.2 Official Examples
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
rwl.readLock().lock();
if (!cacheValid) {
// Must release read lock before acquiring write lock
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// Recheck state because another thread might have
// acquired write lock and changed state before we did.
if (!cacheValid) {
data = ...
cacheValid = true;
}
// Downgrade by acquiring read lock before releasing write lock
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
Copy the code
The code declares a cacheValid variable of volatile type to ensure its visibility. Get the read lock first, release the read lock if the cache is unavailable, obtain the write lock, check the cacheValid value again before changing the data, modify the data, set cacheValid to true, and obtain the read lock before releasing the write lock. At this point, the data in the cache is available, the data in the cache is processed, and the read lock is released. This process is the process of a complete lock the drop, the purpose is to ensure that the data visibility, if the current thread in C after modify the data in the cache, there is no access to read lock but directly release the write lock, so suppose this time another thread T obtain the write lock and modify the data, then C thread cannot perceive data has been modified, the data error. If, following the lock degradation steps, thread C acquires the read lock before releasing the write lock, thread T will be blocked while acquiring the write lock until thread C finishes processing the data and releases the read lock.
5.3 Application Examples
import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteDegrade { private Map<String, Object> map = new HashMap<>(); private ReadWriteLock rwl = new ReentrantReadWriteLock(); private Lock r = rwl.readLock(); private Lock w = rwl.writeLock(); private volatile boolean isUpdate; Public void readWrite() {r.lock(); If (isUpdate) {r.nunlock (); w.lock(); map.put("xxx", "xxx"); r.lock(); w.unlock(); } Object obj = map.get("xxx"); System.out.println(obj); r.unlock(); } public Object get(String key) { r.lock(); System.out.println(thread.currentThread ().getName() + "Read operation is executing.." ); try { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } return map.get(key); } finally { r.unlock(); System.out.println(thread.currentThread ().getName() + "Read finish.." ); } } public void put(String key, Object value) { w.lock(); System.out.println(thread.currentThread ().getName() + "Write operation is executing.." ); try { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } map.put(key, value); } finally { w.unlock(); System.out.println(thread.currentThread ().getName() + "Write completed.." ); }}}Copy the code
Reference article: Read/write Lock ReentrantReadWriteLock lock degradation
6. StampedLock(after JDK8)
6.1 an overview of the
StampedLock is the ReentrantReadWriteLock upgrade. /stæ MPT /
6.1.1 Disadvantages of ReentrantReadWriteLock
- ReentrantReadWriteLock is mutually exclusive – Read and write are mutually exclusive. Read is not mutually exclusive.
- Because of the high number of reads, the writer thread may be hungry (unable to preempt resources).
- ReentrantReadWriteLock Fair lock that can be used. However, fair locks have lower performance than non-fair locks.
- StampedLock improves read/write mutex performance. Read locks do not block write locks. It also improves performance.
6.1.2 Benefits of StampedLock
Implementing a read-like lock does not block a write lock, so how do we ensure that the read and write are consistent? If a write lock occurs while reading, read again. How do you know when you’re reading a lock? – There’s a ticket. If optimistic locking is used, reads and writes are not mutually exclusive. If a pessimistic lock is obtained, the read/write is mutually exclusive.
6.2 Official Examples
Docs.oracle.com/javase/8/do…
lass Point { private double x, y; private final StampedLock sl = new StampedLock(); void move(double deltaX, double deltaY) { // an exclusively locked method long stamp = sl.writeLock(); try { x += deltaX; y += deltaY; } finally { sl.unlockWrite(stamp); Double distanceFromOrigin() {// A read-only method long stamp = sl.tryoptimisticRead (); Double currentX = x, currentY = y; // Read the two fields into the local local variable if (! Sl. Validate (stamp)) {// Check whether an optimistic read lock has occurred at the same time as another write lock. stamp = sl.readLock(); Try {currentX = x; currentX = x; currentX = x; // Read the two fields into the local local variable currentY = y; } finally {sl.unlockread (stamp); } } return Math.sqrt(currentX * currentX + currentY * currentY); Void moveIfAtOrigin(double newX, double newY) {// upgrade // Could instead start with optimistic, not read mode long stamp = sl.readLock(); Try {while (x == 0.0 && y == 0.0) {long ws = sl.tryConvertToWritelock (stamp); // Convert a read lock to a write lock if (ws! = 0L) {// this is to confirm whether the conversion to write lock was successful stamp = ws; // If the ticket is successfully replaced by x = newX; Y = newY; // Break; } else {// If the conversion to write lock fails sl.unlockread (stamp); // We explicitly release the read lock stamp = sl.writelock (); }} finally {sl.unlock(stamp); // Release a read or write lock}}}Copy the code
6.3 Code Examples
import java.util.concurrent.locks.StampedLock; public class StampedLockThread { private int balance; Private StampedLock lock = new StampedLock(); Public void conditionReadWrite(int value) {long stamp = lock.readlock (); long stamp = readLock(); / / to get paper try {/ / multiple loop execution (literally wrote a condition) while (balance > 0) {long writeStamp = lock. TryConvertToWriteLock (stamp); // A read lock can be converted to a write lock if the condition is true. = 0) {stamp = writeStamp; balance += value; break; } else {// not converted to a write lock, here we need to release the read lock first, and then get the write lock lock.unlockread (stamp); Stamp = lock.writelock (); }}finally {lock.unlock(stamp); Public void optimisticRead() {long stamp = lock.tryoptimisticread (); try { int c = balance; // If (! If (! If (! If (! Lock.validate (stamp)) {long readStamp = lock.readlock (); c = balance; stamp = readStamp; } /// } finally { lock.unlockRead(stamp); Public void read2() {long stamp = lock.readLock(); try { lock.tryOptimisticRead(); Int c = balance; System.out.print("read2-stamp:" + stamp + ",balance:" + balance); / /... }finally { lock.unlockRead(stamp); Public void read() {long stamp = lock.readLock(); try { int c = balance; System.out.print("read-stamp:"+stamp+",balance:"+balance); / /... }finally { lock.unlockRead(stamp); Public void write(int value) {long stamp = lock.writelock (); Try {system.out. print("write-stamp:"+stamp+",value:"+value); balance += value; System.out.println(",balance:"+balance); }finally { lock.unlockWrite(stamp); // Unlock}}}Copy the code
6.4 Core Source code
package java.util.concurrent.locks; public class StampedLock implements java.io.Serializable { /** * Exclusively acquires the lock, blocking if necessary * until available. * * @return a stamp that can be used to unlock or convert mode */ Stamp public long writeLock() {long s, next; stamp public long writeLock() {next; // bypass acquireWrite in fully unlocked case only return ((((s = state) & ABITS) == 0L && U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? next : acquireWrite(false, 0L)); } /** * Exclusively acquires the lock if it is immediately available. * * @return a stamp that can be used to unlock or convert mode, Public long tryWriteLock() {long s, next;} public long tryWriteLock() {long s, next; return ((((s = state) & ABITS) == 0L && U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? next : 0L); } /** * Non-exclusively acquires the lock, * * @return a stamp that can be used to unlock or convert mode */ // Non-exclusive lock public long readLock() { long s = state, next; // bypass acquireRead on common uncontended case return ((whead == wtail && (s & ABITS) < RFULL && U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? next : acquireRead(false, 0L)); } /** * Non-exclusively acquires the lock if it is immediately available. * * @return a stamp that can be used to unlock or convert mode, Public long tryReadLock() {for (;;); public long tryReadLock() {for (;;); { long s, m, next; if ((m = (s = state) & ABITS) == WBIT) return 0L; else if (m < RFULL) { if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) return next; } else if ((next = tryIncReaderOverflow(s)) ! = 0L) return next; } } /** * Returns a stamp that can later be validated, or zero * if exclusively locked. * * @return a stamp, Public long tryOptimisticRead() {long s; return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L; } /** * Returns true if the lock has not been exclusively acquired * since issuance of the given stamp. Always returns false if the * stamp is zero. Always returns true if the stamp represents a * currently held lock. Invoking this method with a value not * obtained from {@link #tryOptimisticRead} or a locking method * for this lock has no defined effect or result. * * @param stamp a stamp * @return {@code true} if the lock has not been exclusively acquired * since issuance of the given stamp; Public Boolean validate(long stamp) {u.loadfence (); return (stamp & SBITS) == (state & SBITS); Public void unlockWrite(long stamp) {WNode h; if (state ! = stamp || (stamp & WBIT) == 0L) throw new IllegalMonitorStateException(); state = (stamp += WBIT) == 0L ? ORIGIN : stamp; if ((h = whead) ! = null && h.status ! = 0) release(h); Public void unlockRead(long stamp) {long s, m; WNode h; for (;;) { if (((s = state) & SBITS) ! = (stamp & SBITS) || (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT) throw new IllegalMonitorStateException(); if (m < RFULL) { if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { if (m == RUNIT && (h = whead) ! = null && h.status ! = 0) release(h); break; } } else if (tryDecReaderOverflow(s) ! = 0L) break; Public void unlock(long stamp) {long a = stamp & ABITS, m, s; WNode h; while (((s = state) & SBITS) == (stamp & SBITS)) { if ((m = s & ABITS) == 0L) break; else if (m == WBIT) { if (a ! = m) break; state = (s += WBIT) == 0L ? ORIGIN : s; if ((h = whead) ! = null && h.status ! = 0) release(h); return; } else if (a == 0L || a >= WBIT) break; else if (m < RFULL) { if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { if (m == RUNIT && (h = whead) ! = null && h.status ! = 0) release(h); return; } } else if (tryDecReaderOverflow(s) ! = 0L) return; } throw new IllegalMonitorStateException(); Public long tryConvertToReadLock(long stamp) {} public long tryConvertToWriteLock(long stamp) {}}Copy the code
7. ReentrantReadWriteLock StampedLock, synchronized contrast summary
- StampedLock is cheaper and consumes less money than ReentrantReadWriteLock.
- Synchronized is implemented at the JVM level. It is not only monitored by monitoring tools, but also automatically released by the JVM if an exception occurs during code execution.
- ReentrantLock, ReentrantReadWriteLock, and StampedLock are all locks at the object level. To ensure that the lock is released, you must place unLock() in finally{}.
- StampedLock provides a huge improvement in throughput, especially in the case of more and more reading threads;
- StampedLock has a complex API that makes it easy to misuse other methods for locking operations;
- Synchronized is a good generic lock implementation when there are only a few competitors;
- ReentrantLock is a good generic lock implementation when thread growth is predictable;
- StampedLock is a good addition to Lock. The throughput and performance improvements are impressive enough for many people, but it is not meant to replace Lock. It has some application scenarios, and at least the API is easier to get started with than StampedLock.