Copy-on-write abbreviation Cow, is a kind of optimization strategy used in program design. The basic idea is that from the beginning everyone is sharing the same content, when someone wants to modify the content, it will really copy the content to form a new content and then change, this is a delay lazy strategy. Starting with JDK1.5 Java Concurrency Package provides two concurrent containers implemented using the Copyonwrite mechanism, which are copyonwritearraylist and Copyonwritearrayset. The Copyonwrite container is very useful and can be used in very many concurrent scenarios.
What is a copyonwrite container
The Copyonwrite container is the container that is copied when it is written. The popular understanding is that when we add elements to a container, instead of adding them directly to the current container, the current container is copied, a new container is duplicated, the new container is added, the element is added, and the reference to the original container is pointed to the new container. The advantage of this is that we can read the Copyonwrite container concurrently, without having to lock it, because the current container does not add any elements. So the Copyonwrite container is also a reading and writing separation of ideas, reading and writing different containers.
The realization principle of copyonwritearraylist
Before using Copyonwritearraylist, let's read its source code to understand how it is implemented. The following code is to add elements to the ArrayList, you can find that when added is required to lock, or multithreaded writing will be copied out of n copies.
Public BooleanAdd (e e) {FinalReentrantlock lock = This. Lock; Lock.lock (); Try{object[] elements=GetArray (); intLen =elements.length; Object[] Newelements= arrays.copyof (elements, Len + 1); Newelements[len]=e; SetArray (newelements); return true; } finally{lock.unlock (); } }
There is no need to lock when reading, if more than one thread is adding data to ArrayList at the time of reading, read or read the old data, because the writing will not lock the old ArrayList.
Public E get (int index) { return get (GetArray (), index); }
The JDK does not provide copyonwritemap, we can refer to Copyonwritearraylist to implement one, the basic code is as follows
PackageJuc;Importjava.util.Collection;ImportJava.util.HashMap;ImportJava.util.Map;ImportJava.util.Set; Public classCopyonwritemap<k, v>ImplementsMap<k, v>, cloneable {Private volatileMap<k, v>Internalmap; PublicCopyonwritemap () {Internalmap=NewHashmap<k, v>(); } Publicv put (K key, V value) {synchronized( This) {Map<k, v> newmap =NewHashmap<k, v>(INTERNALMAP); V Val=newmap.put (key, value); Internalmap=Newmap; returnVal; } } PublicV get (Object key) {returnInternalmap.get (key); } Public voidPutall (map<?extendsK?extendsV>NewData) { synchronized( This) {Map<k, v> newmap =NewHashmap<k, v>(INTERNALMAP); Newmap.putall (NewData); Internalmap=Newmap; } }
Implementation is simple, as long as we understand the copyonwrite mechanism, we can implement a variety of copyonwrite containers, and used in different scenarios.
Copyonwrite's application Scenario
Copyonwrite concurrent containers are used for read-write-less concurrency scenarios. such as white list, blacklist, product category to visit and update the scene, if we have a search site, users in this Site search box, enter keywords search content, but some keywords are not allowed to be searched. These keywords that cannot be searched are placed in a blacklist, and the Blacklist is updated every night. When the user searches, it checks that the current keyword is not in the blacklist, and if so, the prompt cannot be searched. The implementation code is as follows:
Package Com.ifeve.book;
Import Java.util.Map;
Import Com.ifeve.book.forkjoin.CopyOnWriteMap;
/**
* Blacklist Service
*
* @author Fangtengfei
*
*/
public class Blacklistserviceimpl {
private static copyonwritemap<string, boolean> Blacklistmap = new copyonwritemap<string, boolean> (
1000);
public static Boolean isblacklist (String ID) {
return Blacklistmap.get (id) = = null? False:true;
}
public static void Addblacklist (String id) {
Blacklistmap.put (ID, boolean.true);
}
/**
* Batch Add blacklist
*
* @param IDs
*/
public static void Addblacklist (map<string,boolean> IDs) {
Blacklistmap.putall (IDS);
}
}
The code is simple, but there are two things to note about using Copyonwritemap:
1. Reduce the expansion overhead. According to the actual needs, initialize the size of the copyonwritemap to avoid the overhead of copyonwritemap expansion when writing.
2. Use bulk Add. Because each time it is added, the container replicates every time, so you can reduce the number of times the container replicates by reducing the number of additions. such as using the Addblacklist method in the above code.
Disadvantages of Copyonwrite
The Copyonwrite container has many advantages, but there are also two problems, namely, memory occupancy and data consistency. So in the development of the time need to pay attention.
memory consumption issues . Because of the copyonwrite of the write-time replication mechanism, so when the write operation, memory will be stationed at the same time the memory of two objects, the old object and the newly written object (note: In the copy is copied only the reference in the container, but at the time of writing will create a new object to add to the new container, The object of the old container is still in use, so there are two copies of the object memory. If these objects occupy a large amount of memory, say 200M or so, then write 100M data in, memory will occupy 300M, then this time is likely to cause frequent Yong GC and full GC. Before we used a service in our system because the copyonwrite mechanism is used to update large objects every night, resulting in a full GC of 15 seconds per night, the application response time also becomes longer.
For memory usage, you can reduce the memory consumption of large objects by compressing the elements in the container, for example, if the elements are all 10 binary numbers, consider compressing them into 36 or 64 binary. Or do not use the Copyonwrite container, but use other concurrent containers, such as Concurrenthashmap.
data consistency issues . The Copyonwrite container can only guarantee the final consistency of the data and cannot guarantee the real-time data consistency. So if you want to write the data that can be read right away, please do not use the Copyonwrite container.
In the STL about C + +, there have been copy-on-write, see Chenhao's "C + + STL String class Copy-on-write", and later, because there are a lot of thread security, it was removed.
Copy-on-write container in concurrent-java