java CopyOnWriteArrayList

CopyOnWriteArrayList这是一个ArrayList的线程安全的变体,其原理大概可以通俗的理解为:初始化的时候只有一个容器,多个线程同时读取数据没有问题,但是后来有人往里面增加了一个数据,这个时候CopyOnWriteArrayList 底层实现添加的原理是先copy出一个容器(可以简称副本),再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。

package com.hts;

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 ListConcurrentTest {
    private static final int THREAD_POOL_MAX_NUM = 10;
    private CopyOnWriteArrayList<String> mList = new CopyOnWriteArrayList<String>();
    public static void main(String args[]){
        new ListConcurrentTest().start();
    }
    private void initData() {
        for(int i = 0 ; i <= THREAD_POOL_MAX_NUM ; i ++){
            this.mList.add("...... Line "+(i+1)+" ......");
        }
    }
    private void start(){
        initData();
        ExecutorService service = Executors.newFixedThreadPool(THREAD_POOL_MAX_NUM);
        for(int i = 0 ; i < THREAD_POOL_MAX_NUM ; i ++){
            service.execute(new ListReader(this.mList));
            service.execute(new ListWriter(this.mList,i));
        }
        service.shutdown();
    }
    private class ListReader implements Runnable{
        private List<String> mList ;
        public  ListReader(List<String> list) {
            this.mList = list;
        }
        @Override
        public void run() {
            if(this.mList!=null){
                for(String str : this.mList){
                    System.out.println(Thread.currentThread().getName()+" : "+ str);
                }
            }
        }
    }
    private class ListWriter implements Runnable{
        private List<String> mList ;
        private int mIndex;
        public  ListWriter(List<String> list,int index) {
            this.mList = list;
            this.mIndex = index;
        }
        @Override
        public void run() {
            if(this.mList!=null){
                //this.mList.remove(this.mIndex);
                this.mList.add("...... add "+mIndex +" ......");
            }
        }
    }
}

如果使用ArrayList 会报错,在同一时间多个线程对同一个List进行读取和增删,会抛出并发异常,如果使用CopyOnWriteArrayList可以解决。
CopyOnWriteArrayList可以解决并发引起的问题,但是在复制过程中产生另一块内存,资源消耗大。

转载:原文出处

posted on 2018-07-12 17:30  天生一对  阅读(118)  评论(0编辑  收藏  举报

导航