Java的集合的集成体系如下

JAVA集合之Arraylist使用方法_ci


ArrayList实现List接口,具有有序和线程不安全,高效的特点(相比vector)。

1.ArrayList的常用方法

public class ArrayLists {
public static void main(String[] args) {
//ArrayList的装箱
ArrayList arrayList=new ArrayList();
arrayList.add(1);
arrayList.add(true);
arrayList.add("tom");
System.out.println(arrayList);
//按索引的顺序移除
arrayList.remove(0);
//遍历输出arraylist
System.out.println(arrayList);
//查看是否含有tom
System.out.println(arrayList.contains("tom"));
System.out.println(arrayList);
//查看是否为空
System.out.println(arrayList.isEmpty());
//清除list
//arrayList.clear();
System.out.println(arrayList);
ArrayList arrayList1=new ArrayList();
//arrayList1.add(1);
arrayList1.add(true);
arrayList1.add("tom");
//查看arraylist是否包含arrylist1的全部元素
System.out.println(arrayList.containsAll((arrayList1)));
//删除arraylist包含arrylist1的全部元素
System.out.println(arrayList.removeAll(arrayList1));
System.out.println(arrayList);


}
}

JAVA集合之Arraylist使用方法_List_02

二 ArrayList源码解读

ArrayList的扩容机制

ArrayList的初始化的长度大小为10,每次添加前判断是否还有空间,若不足,则扩充为当前容量的1.5倍,使用debug代码,将断点打在ArrayList

public class ArraylistSourceCode {
public static void main(String[] args) {
ArrayList list=new ArrayList();
list.add("张");
list.add("王");
list.add("周");
list.add("李");
list.add("张");
list.add("王");
list.add("周");
list.add("李");
list.add("张");
list.add("王");
list.add("周");
list.add("李");

}
}
//ArrayList维护一个Object数组,modcount计数,初始化定义数组长度为10
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

JAVA集合之Arraylist使用方法_System_03

//计数+1
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 如果队列的容量小于 minCapacity是队列的当前的数量
//判断是否越界
if (minCapacity - elementData.length > 0)
//增加空间
grow(minCapacity);
}

JAVA集合之Arraylist使用方法_ci_04

/**
*arraylist第一次插入数据和空间不足都会执行此方法
* */
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//容量直接扩为1.5倍
//>>表示右移一位 /2
//<<表示左移一位 *二
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//将队列重新复制一遍,并重新设置容量
elementData = Arrays.copyOf(elementData, newCapacity);
}

JAVA集合之Arraylist使用方法_ci_05

ArrayList线程不安全以及解决办法

public class ListTest {
public static void main(String[] args) {
//这是个普通list集合添加的操作,如果不加限制,在多线程的环境下会出现 java.util.ConcurrentModificationException
List<String> alist = new ArrayList<>();
for(int i=0;i<=10;i++){

new Thread(()->{
alist.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(alist);
}).start();
}
}
}

JAVA集合之Arraylist使用方法_List_06


官方说法是不允许一个线程在修改集合时,另外的线程对其遍读,否则会抛出异常

JAVA集合之Arraylist使用方法_System_07

//修改的方法如下,使用vector,vector线程安全如果排除contains方法和remove方法不具有原子性的话,因为集合添加会有这个问题
List<String> alist = new Vector<>(); //jdk1.0的东西
for(int i=0;i<=10;i++){

new Thread(()->{
alist.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(alist);
}).start();
}

JAVA集合之Arraylist使用方法_System_08


没有问题

//使用synchonrizedlist
List<String> alist = Collections.synchronizedList(new ArrayList<>()); //一般的解决方法
for(int i=0;i<=10;i++){

new Thread(()->{
alist.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(alist);
}).start();
}

可以实现

//synchronizedList的源码如下 ==》都添加synchonrized
//除了遍历的listIterator方法需要编程人员添加synchonrized
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;

final List<E> list;

SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}

public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}

public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}

public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}

public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}

public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}

public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
}

public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedList<>(list.subList(fromIndex, toIndex),
mutex);
}
}

@Override
public void replaceAll(UnaryOperator<E> operator) {
synchronized (mutex) {list.replaceAll(operator);}
}
@Override
public void sort(Comparator<? super E> c) {
synchronized (mutex) {list.sort(c);}
}
... ...
}

终极方案

/*****
* 读写分离的思想
* 添加容器时,复制容器,往容器添加数据后,使容器指向新的容器,简单来说,类似快照,在用快照替代了原始的
* **/
List<String> alist = new CopyOnWriteArrayList<>();
for(int i=0;i<=10;i++){

new Thread(()->{
alist.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(alist);
}).start();
}

JAVA集合之Arraylist使用方法_System_09

参考链接
​​​ConcurrentModificationException​

​CopyOnWriteArrayList​