Read-write lock
ReentrantReadWriteLock
When the read operation is much higher than the write operation, use read/write locks to allow read-read concurrency and improve performance. Similar to select in a database… from… Lock in Share Mode provides a read() method inside a data container class that protects data with a read lock and a write() method that protects data
public class TestReadWriteLock {
public static void main(String[] args) {
DataContainer dataContainer = new DataContainer();
new Thread(() -> {
dataContainer.read();
}, "read").start();
new Thread(() -> {
dataContainer.write();
}, "write").start(); }}@Slf4j
class DataContainer {
private Object data;
private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
private ReentrantReadWriteLock.ReadLock r = rw.readLock();
private ReentrantReadWriteLock.WriteLock w = rw.writeLock();
public Object read(a) {
log.debug("Get read lock...");
r.lock();
try {
log.debug("read");
sleep(1000);
return data;
} finally {
log.debug("Release read lock..."); r.unlock(); }}public void write(a) {
log.debug("Get write lock");
w.lock();
try {
log.debug("write");
} finally {
log.debug("Release write lock"); w.unlock(); }}}Copy the code
Output:
00:29:24. 932 / read the DEBUG com. Tyroxyz. Multithread. Multi. The DataContainer – get read lock… 00:29:24. 932 [write] the DEBUG com. Tyroxyz. Multithread. Multi. DataContainer – access to write lock 00:29:24. 945 (read) the DEBUG Com. Tyroxyz. Multithread. Multi. The DataContainer – read 00:29:25. 946 / read the DEBUG com. Tyroxyz. Multithread. Multi. The DataContainer – Release read locks… 00:29:25. 946 [write] the DEBUG com. Tyroxyz. Multithread. Multi. The DataContainer – write 00:29:25, 946 [write] the DEBUG Com. Tyroxyz. Multithread. Multi. The DataContainer – write lock release
Matters needing attention
- Read locks do not support condition variables
- Reentry upgrade is not supported: Obtaining a write lock while holding a read lock will cause a permanent wait for obtaining the write lock
r.lock();
try {
w.lock();
try {
/ /...
} finally{ w.unlock(); }}finally {
r.unlock();
}
Copy the code
- Reentrant degradation support: obtain read locks while holding write locks
class CachedData {
Object data;
// Whether the data is valid. If it is invalid, you need to recalculate data
volatile boolean cacheValid;
final ReentrantReadWriteLock rw1 = new ReentrantReadWriteLock();
void processCachedDate(a) {
rw1.readLock().lock();
if(! cacheValid) {// The read lock must be released before the write lock is acquired
rw1.readLock().unlock();
rw1.writeLock().lock();
try {
// Determine whether another thread has acquired the write lock and updated the cache to avoid repeated updates
if(! cacheValid) { data = ... ; cacheValid =true;
}
// Downgrade to a read lock and release the write lock so that other threads can read the cache
rw1.readLock().lock();
} finally{ rw1.writeLock().unlock(); }}// Release read lock when you run out of data
try {
use(data);
} finally{ rw1.readLock().unlock(); }}}Copy the code