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可以解决并发引起的问题,但是在复制过程中产生另一块内存,资源消耗大。
转载:原文出处