Java set List CopyOnWriteArrayList

Reference link:

http://blog.csdn.net/hua631150873/article/details/51306021

Copy-On-Write is referred to as COW. When a collection is to be modified, a copy of the collection is made, the newly copied collection is modified, and the new collection is pointed to the old collection after completion.

View CopyOnWriteArrayList source code

add method

使用final ReentrantLock lock = this.lock;

lock.lock();

Lock before calling the add(...) method to ensure that only one thread can add elements at a time. Use the Arrays.copyOf(...) method to copy out another new array, and the length of the new array is 1 more than the original. After the copy is completed, assign the newly added elements to the new array, and finally assign the new copy array Give the old array, then release the lock in finally.

remove method

To delete an element, the main judgment is whether to delete the last element. If so, copy the length-1 of the original array directly. Otherwise, first copy the front of the array index to the new array, then copy the element after the index to the array, and finally put the new array. Array assigns a reference to the old array.

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).  Returns the element that was removed from the list.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1; 
            if (numMoved == 0) // 判断index是不是最后一个,举例如果原来数组总共有3个元素,len 是 3, index 是 2, 则numMoved是0;
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1]; // 拷贝一个比原来数组长度少一个的数组
                System.arraycopy(elements, 0, newElements, 0, index); // 先拷贝index前半部分,
                System.arraycopy(elements, index + 1, newElements, index, // 再拷贝index+1后面的部分
                                 numMoved);
                setArray(newElements); // 最后将新数组的引用赋值给旧数组
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

Next, look at the source code of the System.arraycopy(...) method

get method

set method

Code example:

Multithreading exceptions are not guaranteed to occur, but there is a high chance of concurrent exceptions when using ArrayList. This problem can be solved by using CopyOnWriteArrayList below. If there is no concurrency exception when using ArrayList, it is recommended to make the thread pool larger.

package com.jerry.entity;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CopyOnWriteListTest {
	
	private static final int THREAD_POOL_MAX_NUM = 10;
//	private List<String> mList = new ArrayList<String>();
	private List<String> mList = new CopyOnWriteArrayList<String>();
	
	public static void main(String[] args) {
		new CopyOnWriteListTest().start();

	}
	
	private void initData() {
		this.mList.add("code_99");
		this.mList.add("code_98");
		this.mList.add("code_97");
		
	}
	
	private void start() {
		initData();
		
		ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_MAX_NUM);
		for(int i=1; i<=THREAD_POOL_MAX_NUM; i++) {
			executorService.execute(new ListReader(this.mList));
			String codeId = "code_"+i;
			executorService.execute(new ListWriter(this.mList, codeId));
		}
		executorService.shutdown();
	}
	
	private class ListReader implements Runnable {
		
		private List<String> rList;
		
		public ListReader(List<String> list) {
			this.rList = list;
		}

		@Override
		public void run() {
			if(this.rList != null) {
				System.out.println("Reader Thread: "+Thread.currentThread().getName()+" --> "+this.rList.toString());
			}
			
		}
		
	}
	
	private class ListWriter implements Runnable {
		private List<String> wList;
		private String codeId;
		
		public ListWriter(List<String> list, String codeId) {
			this.wList = list;
			this.codeId = codeId;
		}

		@Override
		public void run() {
			if(this.wList != null) {
				this.wList.add(codeId);
				System.out.println("Writer Thread: "+Thread.currentThread().getName()+" --> "+this.wList.toString());
			}
			
		}
	}

}

Advantages and disadvantages of CopyOnWriteArrayList:

Advantages: Solve the concurrency problem of multi-threading

shortcoming:

1. There is a problem with memory usage: copy-on-write, there will be two objects in memory. Obviously, the two arrays reside in the memory at the same time. If there is a lot of data in the actual application, the memory will be larger. For this, ConcurrentHashMap can be used instead. Therefore, CopyOnWriteArrayList is not recommended for large objects.

ConcurrentHashMap: https://my.oschina.net/u/3781047/blog/1628709

2. Data consistency: The CopyOnWrite container can only guarantee the final consistency of the data, but cannot guarantee the real-time consistency of the data. Therefore, COW is not recommended for real-time data.

Guess you like

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