Concept
An exclusive lock : This lock can only be held by one thread lock at a time (ReetrantLock
and Synchronized
All exclusive locks )
Shared lock : The lock can be held by multiple threads
Yes ReentrantReadWriteLock for , Its read lock is sharing , Write lock is exclusive . When I write, I write by myself , But it can be read by many people at the same time .
Why write lock and read lock
So we use ReentrantLock When creating locks , Is an exclusive lock , That is to say, only one thread can access it at a time . But there's a read-write separation scenario , I want to read at the same time , Because read locks don't cause data inconsistency , So it can be shared by many people .
There is no problem for multiple threads to read a resource class at the same time , If a thread wants to write shared memory , No other thread should read or write to the resource .
Code implementation
- Implementation of a read-write cache operation , Suppose there is no lock at the beginning , What happens
Simulate it first HashMap Of put
and get
Method :
public class MyCache {
private volatile Map<String,Object> map = new HashMap<>();
// Write method
public void put(String key,Object value) throws InterruptedException {
System.out.println(" Threads "+ Thread.currentThread().getName() +" Are written to the :" + key);
TimeUnit.MILLISECONDS.sleep(300); // Simulate network congestion , Delay 0.3s
map.put(key,value); // Write elements
System.out.println(" Threads "+ Thread.currentThread().getName() +" Write successfully ");
}
// Read method
public void get(String key) throws InterruptedException {
System.out.println(" Threads "+ Thread.currentThread().getName() +" Reading :");
TimeUnit.MILLISECONDS.sleep(300); // Simulate network congestion , Delay 0.3s
Object value = map.get(key); // Read elements
System.out.println(" Threads "+ Thread.currentThread().getName() +" Read complete :" + value );
}
}
test :
public static void main(String[] args) {
MyCache myCache = new MyCache();
// establish 5 Threads write to the cache
for (int i = 0; i < 5; i++) {
final int tempInt = i; //lambda The variable inside the expression must be final
new Thread(() -> {
myCache.put(tempInt + "", tempInt + "");
}, " Threads " + i).start();
}
// establish 5 Thread read cache
for (int i = 0; i < 5; i++) {
final int tempInt = i; //lambda The variable inside the expression must be final
new Thread(() -> {
myCache.get(tempInt + "");
}, " Threads " + i).start();
}
}
Running result display :
resolvent
The above code is not locked , This will cause the thread to be in progress Write operation When , Frequently interrupted by other threads , So there is no atomicity , Now , We need to use read-write lock to solve the problem .
Create a read-write lock :
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
// It's a lock that integrates reading and writing , In use , Need to transform
When we're writing , It needs to be converted to a write lock :
// Create a write lock
rwLock.writeLock().lock();
// Write lock Release
rwLock.writeLock().unlock();
When you're reading , After converting to read lock
// Create a read lock
rwLock.readLock().lock();
// Read the lock Release
rwLock.readLock().unlock();
The difference between read lock and write lock is , Write lock can only be entered by one thread at a time , Perform write operations , Read lock means that multiple threads can enter at the same time , To read .
We will take MyCache Class put Method Add a write lock to the front of the , Finally release the lock .get Method Add a read lock at the front of the , Finally release the lock .
Finally, let's look at the running results after adding read-write lock :
From the running results, we can see that , Write operations are performed one thread at a time , And there's no interruption in the middle , And the read operation , At the same time 5 Threads in , And then concurrent read operations .