cool hit counter Principle of ReentrantReadWriteLock class under concrrent class and its usage_Intefrankly

Principle of ReentrantReadWriteLock class under concrrent class and its usage


  1. Introduction of the ReentrantreadWriteLock class

   Subclasses under the Lock interface exist for the ReentrantLock subclass, which is a thread synchronization handler class; see XXX for a detailed description of the ReentrantLock class.

   Lock is more object-oriented than the synchronized approach in the traditional threaded model, and similar to locks in life, a lock should be an object itself. For the code fragments executed by two threads to achieve the effect of synchronous mutual exclusion, they must use the same Lock object.

The ReentrantReadWriteLock class is a subclass of ReentrantLock; it is an implementation class of the ReadWriteLock interface; it is a multi-threaded read and write related processing class; it is subdivided into read and write locks.

   Read and write locks: divided into read and write locks, multiple read locks are not mutually exclusive, read and write locks are mutually exclusive, which is controlled by jvm itself, we just need to put the appropriate lock. If your code only reads data and can have many people reading at the same time, but not writing at the same time, then put a read lock on; if your code modifies data and only one person is writing and cannot read at the same time, then put a write lock on. In short, read lock on read, write lock on write!

ReadWriteLock interface: ReadWriteLock, its specific implementation class is: ReentrantReadWriteLock readlock() and writelock() to obtain read and write locks to unlock operations.

In a multi-threaded environment, reading and writing to the same data involves thread safety issues. For example, while one thread is reading data, another thread is writing data, and this leads to inconsistency in the data before and after; while one thread is writing data, another thread is also writing, again leading to inconsistency in the data seen before and after the thread.

This time you can add a mutual exclusion lock to the read and write methods, which only allows one read or write operation from one thread at any time, and not from other threads, which is a solution to the above problem, but the efficiency is greatly reduced. Because in real business scenarios, a copy of the data, the number of operations to read the data is usually higher than the number of operations to write the data, and the read-read operation between threads is not involved in thread safety, there is no need to join the mutually exclusive lock, as long as the lock during the read-write, write-write on the line.

   For cases like the above, a read/write lock is the best solution! One of its implementation classes: ReentrantReadWriteLock - as the name suggests is a reentrant read and write lock that allows multiple read threads to get ReadLock, but only one write thread to get WriteLock

Mechanisms for read and write locks.

 "read-read" non-exclusive

 "read- write" mutually exclusive

 " write- write" mutually exclusive

ReentrantReadWriteLock will use two locks to solve the problem, a read lock and a write lock.

Prerequisites for a thread to enter a read lock.

   1. No write locks from other threads

     2. There is no write request, or there is a write request but the calling thread and the thread holding the lock are the same thread

Prerequisites for accessing the write lock.

     1. No read locks from other threads

     2. No write locks from other threads

Concepts to know in advance.

Lock downgrading: from a write lock to a read lock.

   Lock upgrade: from a read lock to a write lock.

   Read locks can be shared by multiple threads, Write locks are single-threaded exclusivity The. This means that write locks have a higher concurrency limit than read locks, This could be the upgrade/ Origin of downgraded names。

   The following code creates a deadlock because a write lock is applied in the same thread without releasing the read lock, which is Lock upgrade, ReentrantReadWriteLock is not supported The.

 ReadWriteLock rtLock = new ReentrantReadWriteLock();
 rtLock.readLock().lock();
 System.out.println("get readLock.");
 rtLock.writeLock().lock();
 System.out.println("blocking");

ReentrantReadWriteLock supports lock degradation, the The following code will not generate a deadlock.

ReadWriteLock rtLock = new ReentrantReadWriteLock();
rtLock.writeLock().lock();
System.out.println("writeLock");

rtLock.readLock().lock();
System.out.println("get read lock");

   This code above does not cause a deadlock, but it does not release the lock properly. Downgrading from a write lock to a read lock does not automatically release the write lock acquired by the current thread, it still needs to be released by the display, otherwise another thread will never acquire the write lock. ,

============ I'll explain ReentrantReadWriteLock in practice with a caching mechanism in a real scenario below ============

Let's start with a good example code example of Cache provided to us in the javaodoc documentation for ReentrantReadWriteLock.

 1 class CachedData {
 2   Object data;
 3   volatile boolean cacheValid;
 4   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
 5 
 6   public void processCachedData() {
  7 rwl.readLock().lock();  // Read locks can be used by multiple threads simultaneously when read locks are added; ---- 1
  8 if (!cacheValid) { //one of the threads enters the judgment, and if it's empty, it goes to the if statement, and then unlocks the read lock
 9       // Must release read lock before acquiring write lock
 10 rwl.readLock().unlock();  //Read Lock Unlock At this point the read lock is unlocked and the blocking write thread at 1 gains execution access to that part of the code and then adds the lock.
 11 rwl.writeLock().lock();  //Write locking locking
12       try {
13         // Recheck state because another thread might have,acquired write lock and changed state before we did.
 14 if (!cacheValid) { // must be judged here If not, the lower lock is downgraded and the upper read threads execute multiple assignments to this code.
15           data = ...
16           cacheValid = true;
17         }
 18 // Downgrade the write lock by acquiring the read lock before releasing the write lock (note that the write lock has not been released at this point)
 19 rwl.readLock().lock();  //Write lock Lock downgrade
20       } finally {
 21 rwl.writeLock().unlock();  // Release the write lock when the read lock is already held
22       }
23     }
24 
25     try {
26       use(data);
27     } finally {
28       rwl.readLock().unlock();
29     }
30   }
31 }

The above code adds locks in the following order.

1.rwl.readLock().lock();

2.rwl.readLock().unlock();

3.rwl.writeLock().lock();

4.rwl.readLock().lock(); // lock downgrade

5.rwl.writeLock().unlock();

6.rwl.readLock().unlock();

The above process is explained in its entirety.

1. When multiple threads access the cache object at the same time, they all add a read lock on the current object, after which one of the threads takes precedence to see if the data data is empty. [Locking sequence number: 1]

2. The thread currently viewing finds no value then releases the read lock and immediately adds a write lock to prepare to write the cached data. (If you don't understand why the read lock is released, you can check the prerequisites for entering the write lock above) [Locking sequence number: 2 and 3]

3. The reason why it also determines if it's null again (!cacheValid) is because the second and third threads are also required to determine if it's null when they get the right to read, otherwise the data will be written repeatedly.

4. Write data and then perform a read lock degradation before releasing the write lock. [Locking sequence number: 4 and 5]

5. The final read lock is released before the final data data is returned. [Locking sequence number: 6]

   If you do not use the lock degradation function, such as releasing the write lock first and then acquiring the read lock, during this get process, there may be other threads competing for the write lock or updating the data Then the data acquired is the data updated by other threads, which may cause data contamination, i.e., create the problem of dirty reads.

Next, let's implement a caching example that actually tends to be used in a real production environment.

 1 import java.util.HashMap;
 2 import java.util.Map;
 3 import java.util.concurrent.locks.ReadWriteLock;
 4 import java.util.concurrent.locks.ReentrantReadWriteLock;
 5 
 6 public class CacheDemo {
 7     /**
  8 * cache, here assuming that about 1000 cache objects need to be stored, with a default load factor of 0.75, the capacity = 750, roughly estimating a chain length of 5 per node
  9 * Then the length of the array is approximately: 150,and there is rain set map size is generally 2 of the index, then the nearest number is: 128
10      */
11     private Map<String, Object> map = new HashMap<>(128);
12     private ReadWriteLock rwl = new ReentrantReadWriteLock();
13     public static void main(String[] args) {
14 
15     }
16     public Object get(String id){
17         Object value = null;
 18 rwl.readLock().lock();// first turn on the read lock and go from the cache to fetch
19         try{
                if(map.get(id) == null){ //if no read lock is released in the cache, put a write lock on
22                 rwl.readLock().unlock();
23                 rwl.writeLock().lock();
24                 try{
 25 if(value == null){ //prevent duplicate query assignments in multiple write threads
26                         value = "redis-value";  // At this point you can go to the database and look up, Here's a simple simulation
27                     }
 28 rwl.readLock().lock();  // Adding a read lock to downgrade a write lock, if you don't understand, you can see the principle of lock downgrading and maintaining atomicity of read data above.
29                 }finally{
 30 rwl.writeLock().unlock();  // Release the write lock
31                 }
32             }
33         }finally{
34 rwl.readLock().unlock();  // Final release of the read lock
35         }
36         return value;
37     }
38 }

Tip. The read-write lock is followed by a conditional blocking used in conjunction with it to enable communication between threads; it is Condition. Specific reference to the blog. Concurrent Library Application No. 6 & conditional blockageCondition application


Recommended>>
1、Bursting onto GitHub Someone is planning to take machine learning in 100 days with this program
2、Qinan Internet Police Warning Notice on Security Vulnerability of Nginx web server
3、China Optical Smart Manufacturing 2025 promotes new opportunities for the industry CIOE Highend Forum invites you to discuss initiatives
4、StarShareShenzhen
5、Agile development with shortcycle iterative delivery

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号