Talk about Concurrency - Copy-On-Write Container in Java

Copy-On-Write, referred to as COW, is an optimization strategy used in programming. The basic idea is that everyone is sharing the same content from the beginning. When someone wants to modify the content, they will actually copy the content out to form a new content and then change it. This is a kind of delayed laziness. Strategy. Since JDK1.5, the Java concurrent package provides two concurrent containers implemented by the CopyOnWrite mechanism, which are CopyOnWriteArrayList and CopyOnWriteArraySet. The CopyOnWrite container is very useful and can be used in many concurrent scenarios.

What is a CopyOnWrite container

A CopyOnWrite container is a copy-on-write container. The popular understanding is that when we add elements to a container, we do not directly add to the current container, but first copy the current container, copy a new container, and then add elements to the new container. After adding elements, Then point the reference of the original container to the new container. The advantage of this is that we can read the CopyOnWrite container concurrently without locking, because the current container will not add any elements. Therefore, the CopyOnWrite container is also a kind of separation of reading and writing, reading and writing different containers.

 

Implementation 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. It can be found that locking is required when adding, otherwise, N copies will be copied when multi-threaded writing.

public boolean add(T e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {

        Object[] elements = getArray();

        int len = elements.length;
        // 复制出新数组

        Object[] newElements = Arrays.copyOf(elements, len + 1);
        // 把新元素添加到新数组里

        newElements[len] = e;
        // 把原数组引用指向新数组

        setArray(newElements);

        return true;

    } finally {

        lock.unlock();

    }

}

final void setArray(Object[] a) {
    array = a;
}

The implementation is very simple, as long as we understand the CopyOnWrite mechanism, we can implement various CopyOnWrite containers and use them in different application scenarios.

Application scenarios of CopyOnWrite

CopyOnWrite concurrent containers are used for concurrent scenarios with more reads and fewer writes. For example, whitelist, blacklist, access and update scenarios of commodity categories, if we have a search website, users enter keywords to search for content in the search box of this website, but some keywords are not allowed to be searched. These keywords that cannot be searched will be placed in a blacklist, which is updated every night. When the user searches, it will check whether the current keyword is in the blacklist. If it is, it will prompt that the keyword cannot be searched. The implementation code is as follows:

package com.ifeve.book;

import java.util.Map;

import com.ifeve.book.forkjoin.CopyOnWriteMap;

/**
 * 黑名单服务
 *
 * @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);
    }

    /**
     * 批量添加黑名单
     *
     * @param ids
     */
    public static void addBlackList(Map<String,Boolean> ids) {
        blackListMap.putAll(ids);
    }

}

The code is simple, but there are two things to be aware of when using CopyOnWriteMap:

1. Reduce the expansion cost. Initialize the size of CopyOnWriteMap according to actual needs to avoid the overhead of expanding CopyOnWriteMap during writing.

2. Use Bulk Add. Because each time you add, the container will be copied every time, so reducing the number of additions can reduce the number of times the container is copied. 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 usage and data consistency. So you need to pay attention when developing.

Memory usage issue . Because of the copy-on-write mechanism of CopyOnWrite, when a write operation is performed, the memory of two objects will reside in the memory at the same time, the old object and the newly written object (note: when copying, only the reference in the container is copied, It's just that new objects are created and added to the new container when writing, and the objects of the old container are still in use, so there are two object memory). If the memory occupied by these objects is relatively large, such as about 200M, then 100M of data is written in, and the memory will occupy 300M, so this time is likely to cause frequent Yong GC and Full GC. Previously, a service was used in our system. Due to the use of the CopyOnWrite mechanism to update large objects every night, Full GC occurred every night for 15 seconds, and the application response time also became longer.

For the problem of 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 decimal numbers, you can consider compressing them into 36 or 64 hexadecimal. 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 eventual consistency of the data, but not the real-time consistency of the data. So if you want the written data to be read immediately, please do not use the CopyOnWrite container.

Regarding the C++ STL, there was also a Copy-On-Write gameplay. See Chen Hao's "Copy-On-Write in the C++ STL String Class ". Later, because of many thread safety issues, it was removed. .

Reprinted from Concurrent Programming Network – ifeve.com Link to this article: Talk about Concurrency - Copy-On-Write Container in Java

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325451977&siteId=291194637