• Java并发包中CopyOnWrite容器相关类简介


    简介

    本文是主要介绍,并发容器CopyOnWriteArrayList和CopyOnWriteArraySet(不含重复元素的并发容器)的基本原理和使用示例。

    欢迎探讨,如有错误敬请指正

    如需转载,请注明出处 http://www.cnblogs.com/nullzx/


    1. CopyOnWriteArrayList

    从类的名字我们可以看出,该类是基于ArrayList类实现的。而CopyOnWrite的意思显然借鉴了操作系统中写时拷贝的思想。该容器主要有以下特点:

    1)读取该容器中元素时,不加锁。

    2)写操作,会加锁,也就是说多个线程进行写入操作时会逐个获取锁后进行写入。

    3)写操作不会影响读操作,也就是说线程要进行读操作时,不会因为有线程正在进行写操作而阻塞。

    下面是写操作源代码

        public E set(int index, E element) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                E oldValue = get(elements, index);
    
                if (oldValue != element) {
                    int len = elements.length;
                    Object[] newElements = Arrays.copyOf(elements, len);
                    newElements[index] = element;
                    setArray(newElements);
                } else {
                    // Not quite a no-op; ensures volatile write semantics
                    setArray(elements);
                }
                return oldValue;
            } finally {
                lock.unlock();
            }
        }
    

    工作原理:在CopyOnWriteArrayList类中,定一了一个数组private transient volatile Object[] array;容器中存储的对象的索引都会放在这个数组中。

    写操作首先会获取锁。当获取锁成功后,复制该数组到一个新的数组newElements中,然后修改或者添加某个元素(注意这个时候如果有线程来读取该数组中的某个值,由于读操作不需要获取锁,所以不会被阻塞,但是可能不能读取到最新修改后的值)。修改后,让array指向经过修改后的新数组newElements,原array指向的数组会被垃圾回收器回收。

    下面的代码是CopyOnWriteArrayList的演示例程

    package javalearning;
    
    import java.util.Random;
    import java.util.concurrent.CopyOnWriteArrayList;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    
    /*CopyOnWriteArrayList演示例程*/
    public class CopyOnWriteArrayListDemo {
    	/*定义一个CopyOnWriteArrayList对象,读线程和写线程会同时使用它*/
    	private CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
    	{
    		/*对CopyOnWriteArrayList对象初始化*/
    		cowal.add(1);
    		cowal.add(2);
    		cowal.add(3);
    	}
    	
    	private Random rnd = new Random();
    	
    	public class ReadThread implements Runnable{
    		private String id;
    		
    		public ReadThread(String id){
    			this.id = id;
    		}
    		
    		@Override
    		public void run() {
    			try {
    				Thread.sleep(rnd.nextInt(1000));
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			/*读线程会打印出CopyOnWriteArrayList对象的所有数值*/
    			System.out.println(id + " " + cowal.toString());
    		}
    		
    	}
    	
    	public class WriteThread implements Runnable{
    		
    		/*写线程会将CopyOnWriteArrayList对象的所有数值加1*/
    		@Override
    		public void run() {
    			for(int i = 0; i < cowal.size(); i++){
    				int x = cowal.get(i);
    				
    				/*每修改一个元素之前加锁*/
    				cowal.set(i, x+1);
    				/*修改完一个元素后释放锁*/
    				
    				try{
    					Thread.sleep(rnd.nextInt(1000));
    				}catch(InterruptedException e){
    					e.printStackTrace();
    				}
    			}
    		}
    		
    	}
    	
    	public static void main(String[] args){
    		ExecutorService es = Executors.newCachedThreadPool();
    		CopyOnWriteArrayListDemo demo = new CopyOnWriteArrayListDemo();
    		/*创建两个读线程*/
    		es.execute(demo.new ReadThread("r1"));
    		es.execute(demo.new ReadThread("r2"));
    		/*创建两个写线程*/
    		es.execute(demo.new WriteThread());
    		es.execute(demo.new WriteThread());
    		
    		es.shutdown();
    		while(!es.isTerminated()){
    			;
    		}
    		System.out.println("=====================");
    		/*CopyOnWriteArrayList对象中的最终值*/
    		System.out.println("eventual " + demo.cowal.toString());
    	}
    }
    

    全部结束后,最终结果和我们预想的一致。

    r2 [2, 3, 3]
    r1 [2, 4, 3]
    =====================
    eventual [2, 4, 5]
    

    2. CopyOnWriteArraySet

    CopyOnWriteArraySet是一个不存贮重复对象的写时拷贝容器。它的实现的原理很简单,在其内部定义了一个CopyOnWriteArrayList对象al,当向该容器添加一个对象时,会调用addIfAbsent方法。

        public boolean add(E e) {
            return al.addIfAbsent(e);
        }
    

    3. 参考内容

    [1] 聊聊并发-Java中的Copy-On-Write容器 | 并发编程网 – ifeve.com

    [2] Java并发编程:并发容器之CopyOnWriteArrayList(转载)

  • 相关阅读:
    微信h5下拉隐藏网页,还有取消页面滑动
    vuejs中使用递归嵌套组件
    运行gitbook init命令报错及问题解决办法
    利用python生成gitbook目录文件
    通过Appium日志,分析其运行原理
    字符串两两更换位置
    Dockerfile启动的程序,内存不断增长问题
    测试流程优化
    APP测试面试题(一)
    关于面试总结13-app测试面试题
  • 原文地址:https://www.cnblogs.com/nullzx/p/7455919.html
Copyright © 2020-2023  润新知