1) Advantages
When multiple threads read and modify a resource, we used to use the synchronized synchronization lock, which has a performance loss. In many cases, resource objects are always read in a large number of concurrent ways, occasionally, there is a thread to modify. That is to say, the main thread is read and the modification is not frequent. Therefore, we use reentrantreadwritelock in jdk5.0 to achieve higher concurrency performance than synchronized, high concurrency performance is the main purpose of my use of jdk5.0, rather than the design advantages such as annotation and generics.
Reentrantreadwritelock is used in a large number in the cache, because the objects in the cache are always shared with a large number of read operations, and occasionally modify the sub-objects in this object, such as the status, we can use reentrantreadwritelock to directly update sub-objects with short lifecycles in the root object in the memory without relying on the database lock. This is an improvement in getting rid of the database lock.
2) Use
Reentrantreadwritelock competitive conditions
Reentrantreadwritelock uses two locks to solve the problem, one reading lock and one write lock.
Prerequisites for a thread to enter the read lock:
There is no write lock for other threads,
No write request or write request, but the call thread and the thread holding the lock are the same
Prerequisites for a thread to enter the write lock:
No read locks for other threads
No write locks from other threads
...... Private Someclass; // Locked Resource Private Final Readwritelock lock = New Reentrantreadwritelock (); Private Final Lock r = Lock. readlock (); Private Final Lock W = Lock. writelock ();...... // Read Method ...... R. Lock (); Try {Result = Someclass. somemethod ();} Catch (Exception e ){ // Process } Finally {R. Unlock ();}....... // Write Method ...... // Generate a new someclass instance tempsomeclass ....... W. Lock (); Try { // Release old resources This . Someclass. Dispose (); // Update a new instance This . Someclass = Tempsomeclass ;} Finally {W. Unlock ();}.......
3) Performance Testing
Next we will compare the performance of using reentrantreadwritelock and not using any lock:
We use 100 read threads for concurrent stress tests and find that there is no performance loss in the case of 100% read,
Then we added a write thread on the basis of 100 read threads and wrote it once per minute, with almost no performance loss.
4) Summary
The use of reentrantreadwritelock can be promoted to most read scenarios with a small number of writes. Because there is no competition between read threads, the performance is much better than that of sychronzied.
If you need more precise control over the cache, using reentrantreadwritelock is also a solution.
Readwritelock must strictly differentiate read/write operations. If the read operation uses a write lock, the read throughput is reduced. If the write operation uses a read lock, data errors may occur.
In addition, reentrantreadwritelock has the following features:
- Fairness
- The non-fair lock (default) is the same as the non-fair nature of the exclusive lock. Because there is no lock competition between read threads, read operations are not fair and non-fair. During write operations, since the write operation may immediately obtain the lock, one or more read or write operations will be postponed. Therefore, the throughput of the unfair lock is higher than that of the fair lock.
- When the fair lock uses the clh queue of AQS to release the currently held lock (read lock or write lock), The write lock is preferentially assigned to the write thread with the longest wait time, the premise is that the waiting time of the write thread is longer than that of all read threads. If a thread holds a write lock or a write thread is waiting, all threads (including read and write threads) that attempt to obtain a fair lock (non-reentrant) will be blocked, until the first write thread releases the lock. If the waiting time of the read thread is longer than that of the write thread, the read thread will obtain the lock once the previous write thread releases the lock.
-
- Reconnection
- The read/write lock allows the read and write threads to obtain the read or write locks again in the order of request locks. Of course, the read thread can obtain the re-entry lock only when the write thread releases the lock.
- The write thread can obtain the read lock again after obtaining the write lock, but the read thread cannot obtain the write lock after obtaining the read lock.
- In addition, the read/write lock supports a maximum of 65535 recursive write locks and 65535 recursive read locks.
-
- Lock downgrade
- After the write thread acquires the write lock, it can obtain the read lock and then release the write lock. In this way, the lock is changed from the write lock to the read lock, thus realizing the lock downgrade feature.
-
- Lock upgrade
- Read locks cannot be directly upgraded to write locks. Because all read locks need to be released to obtain a write lock, a deadlock will occur if two read lock views get the write lock and do not release the read lock.
-
- Lock acquisition interrupted
- Both read locks and write locks can be interrupted during lock acquisition. This is consistent with the exclusive lock.
- Condition variable
- The write lock supports conditional variables. This is consistent with the exclusive lock, but the read lock does not allow conditional variables.
UnsupportedoperationexceptionException.
-
- Number of duplicates
- The maximum number of read locks and write locks can be 65535 (including the number of retries ).