Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Why does CopyOnWrite need ReadWriteLock again?

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article will explain in detail why CopyOnWrite has to have ReadWriteLock, the content of the article is of high quality, so the editor will share it for you as a reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.

About the CopyOnWrite container, but it also has some disadvantages:

Memory footprint problem: because CopyOnWrite's write-time replication mechanism has memory for two array objects every time it writes, if this array object takes up a large amount of memory, frequent writes will result in frequent Yong GC and Full GC

Data consistency problem: CopyOnWrite container can only guarantee the final consistency of data, not the real-time consistency of data. The thread of the read operation may not immediately read the newly modified data because the modification occurs on the copy. But in the end, the modification will complete and update the container, so this is the ultimate consistency. At that time, it was said that to solve these two shortcomings, we can use Collections.synchronizedList () to replace, find a nothing more than the addition, deletion, modification and search methods of list have added synchronized implementation. We know that synchronized is actually an exclusive lock (exclusive lock). But in this way, there will be a performance problem. For the scenario of more reading and less writing, you have to acquire the lock every time you read, and then release the lock after reading, so that every request for reading will have to acquire the lock. However, reading will not cause data insecurity, which will cause a performance bottleneck. In order to solve this problem, there is a new kind of lock, read-write lock (ReadWriteLock).

What is a read-write lock

According to the name, we can also guess that there are two locks, namely, the read lock and the write lock. The read lock allows multiple readers to acquire it at the same time, but when the writer thread accesses it, all readers and other writer threads are blocked. The write lock can only be successful by one writer thread at a time, and the rest will be blocked. Read-write lock actually maintains two locks, one read lock and one write lock. By distinguishing between read lock and write lock, concurrency is greatly improved compared with exclusive lock in the case of more read and write less. The implementation of read-write locks in java is ReentrantReadWriteLock, which has the following features:

Fairness selection: support unfair (default) and fair lock acquisition, throughput is still unfair better than fair

Reentrant: support reentrant, read lock can be acquired again after acquisition, write lock can be acquired again after write lock acquisition, and read lock can also be acquired at the same time

Lock degradation: follow the order of acquiring a write lock, acquiring a read lock and then releasing the write lock. A write lock can be degraded to a read lock.

The use of ReentrantReadWriteLock

Let's take an example of https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html from the official website to see how it is used.

Class RWDictionary {private final Map m = new TreeMap (); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock (); private final Lock r = rwl.readLock (); private final Lock w = rwl.writeLock (); public Data get (String key) {r.lock (); try {return m.get (key);} finally {r.unlock ();}} public String [] allKeys () {r.lock (); try {return m.keySet (). ToArray () } finally {r.unlock ();}} public Data put (String key, Data value) {w.lock (); try {return m.put (key, value);} finally {w.unlock ();}} public void clear () {w.lock (); try {m.clear ();} finally {w.unlock ();}

This is very simple and straightforward to use, basically the same as the use of ReentrantLock, acquire the write lock when you write, release the write lock when you finish writing, get the read lock when you read, and release read and write when you finish reading.

Analysis on the implementation of read-write Lock

We know that ReentrantLock controls the state of the lock through state, and the previously introduced "Java high concurrent programming foundation three sharp weapons Semaphore", "Java high concurrent programming foundation three sharp weapons CountDownLatch", "Java high concurrent programming foundation three sharp weapons CyclicBarrier" are all realized through state. There is no doubt that ReentrantReadWriteLock is also achieved through AQS's state, but state is an int value and how to read locks and write locks.

Analysis on the implementation of read-write Lock State

If we have seen the source code of the thread pool, we know that the state and number of threads of the thread pool are controlled by an atomic variable of int type (high 3 bits hold running state, low 29 bits hold threads). The same ReentrantReadWriteLock controls the state of read and write through the high 16 bits and low 16 bits of a state, respectively.

Let's take a look at how it separates reading and writing through a field.

Static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 SHARED_SHIFT;} / * * Returns the number of exclusive holds represented in count * / static int exclusiveCount (int c) {return c & EXCLUSIVE_MASK;}

SharedCount: the number of read locks is to shift the synchronization status (int c) to the unsigned right 16 bits, that is, to take the higher 16 bits of the synchronization state.

ExclusiveCount: the number of write locks we need to look at the static variable EXCLUSIVE_MASK: it is 1 to move 16 bits to the left and then minus 1, that is, 0X0000FFFF, (1 MAX_COUNT) throw new Error ("Maximum lock count exceeded"); / / Reentrant acquire gets the write lock setState (c + acquires); return true } / / judgement of writerShouldBlock fair lock and unfair lock if (writerShouldBlock ()) |! compareAndSetState (c, c + acquires) return false; setExclusiveOwnerThread (current); return true;}

After writing the lock, it must be the read lock because the read lock is a shared lock, so you should rewrite the tryAcquireShared without sticking the code, and the read lock is almost the same as the read lock. In fact, it is relatively easy to figure out AQS and then look at these things that are implemented based on AQS.

Upgrade and downgrade of read-write lock

We mentioned earlier that read-write locks can be degraded, but did not say whether they can be upgraded. Let's take a look at what lock demotion and lock upgrade are.

Lock degradation: from a write lock to a read lock; its process is to hold the write lock first, acquire the read lock, and then release the write lock. If you hold a write lock, release the write lock and then acquire the read lock. This is not a lock degradation.

Why lock and downgrade?

Mainly to ensure the visibility of the data, if the current thread does not acquire the read lock but releases the write lock directly, suppose that another thread (marked as thread T) acquires the write lock and modifies the data. then the current thread is not aware of thread T's data update. If the current thread acquires the read lock, that is, following the step of lock degradation, thread T will be blocked until the current thread uses the data and releases the read lock before thread T can acquire the write lock for data update. From "the Art of Java concurrent programming"

Lock upgrade: from read lock to write lock. First hold the read lock, and then acquire the write lock (which will not succeed) because the acquisition of the write lock is an exclusive lock, and if a read lock is occupied, the write lock will be placed in the queue to wait until all the read locks have been released.

In the case of stand-alone read-write lock, how to implement a distributed read-write lock?

How to solve the hunger problem of ReentrantReadWriteLock? (ReentrantReadWriteLock implements read-write separation, so if you want to acquire read locks, you must make sure that there are no other read-write locks at present, but once there are many reads, it becomes more difficult to acquire write locks, because read locks are likely to exist all the time. The write lock cannot be obtained.)

About why CopyOnWrite should have ReadWriteLock to share here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report