如何做自己的个人网站,刚做的网站怎么才能搜索到,柒零叁网站建设,大连市建设局网站基本简介#xff1a;
是Java中的一个线程安全的List实现#xff0c;也是ArrayList 的安全版本#xff0c;所以就不会有ArrayList 的并发修改异常 的问题产生了
原理
每次在对 List 进行修改时#xff0c;创建一个新的副本#xff08;即拷贝#xff09;#xff0c;而不…基本简介
是Java中的一个线程安全的List实现也是ArrayList 的安全版本所以就不会有ArrayList 的并发修改异常 的问题产生了
原理
每次在对 List 进行修改时创建一个新的副本即拷贝而不是直接在原始列表上进行修改。
在创建新的副本时CopyOnWriteArrayList会复制整个内部数组并在副本上进行修改操作。所以读操作是不会被阻塞的因为读取操作可以同时在原始列表和新创建的副本上进行。
由于每次修改都会创建一个新的副本所以CopyOnWriteArrayList适用于读取操作频繁、写入操作较少的场景。它是可以避免读与写之间的竞争条件从而提供了较好的并发性能。
虽然CopyOnWriteArrayList提供了线程安全的读取操作但写入操作的性能相对较低因为每次写入操作都需要复制整个内部数组。因此如果需要频繁进行写入操作或对 List 的实时性要求较高可能不适合使用CopyOnWriteArrayList。
总的来说就是CopyOnWriteArrayList的原理是通过创建副本来实现线程安全的读取操作避免了读写竞争条件但写入操作的性能相对较低。
弊端
1、 每次都要赋值浪费很大的内存空间
2、读线程可能读不到正在写入的数据是无法保持 数据的实时一致只能保证数据的最终一致性。
源码解释
public class CopyOnWriteArrayListE implements ListE, RandomAccess, Cloneable, java.io.Serializable {
// 此处是和ArrayList一样的
}使用的锁
final transient ReentrantLock lock new ReentrantLock();装载数组
private transient volatile Object[] array;final Object[] getArray() {return array;
}final void setArray(Object[] a) {array a;
}
构造器
// 无参构造器
public CopyOnWriteArrayList() {setArray(new Object[0]);
}// 有参构造器
public CopyOnWriteArrayList(Collection? extends E c) {Object[] elements;if (c.getClass() CopyOnWriteArrayList.class)elements ((CopyOnWriteArrayList?)c).getArray();else {elements c.toArray();if (c.getClass() ! ArrayList.class)elements Arrays.copyOf(elements, elements.length, Object[].class);}setArray(elements);
}
public CopyOnWriteArrayList(E[] toCopyIn) {setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
读
get
get(int index) 返回此列表中指定位置的元素。 //返回此列表中指定位置的元素。
public E get(int index) {return get(getArray(), index);
}
//获取数组
final Object[] getArray() {return array;
}get(Object[] a, int index) 返回此列表中指定位置的元素。 private transient volatile Object[] array;private E get(Object[] a, int index) {return (E) a[index];
}contains
contains(Object o) 如果此列表包含指定元素则返回true 。更正式地说当且仅当此列表包含至少一个元素e且满足(onull ? enull : o.equals(e))时才返回true public boolean contains(Object o) {Object[] elements getArray();// 遍历集合找到返回true 否则返回falsereturn indexOf(o, elements, 0, elements.length) 0;
}containsAll(Collection? c) 如果此列表包含指定集合的所有元素则返回true public boolean containsAll(Collection? c) {Object[] elements getArray();int len elements.length;// 遍历指定集合在挨个遍历原数组中的元素进行匹配找不到就返回不存在falsefor (Object e : c) {if (indexOf(e, elements, 0, len) 0)return false;}// 否则返回truereturn true;
}写
set
set(int index, E element) 将此列表中指定位置的元素替换为指定元素。 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;// 对原来的数组进行copy并设置新数组的容量 就是 原数组的容量 Object[] newElements Arrays.copyOf(elements, len);// 修改新数组指定位置的元素newElements[index] element;// 新数组 变为 下次getArray 的数组setArray(newElements);} else {// 修改的值和原来的一样不用修改setArray(elements);}// 返回旧的值return oldValue;} finally {lock.unlock();}
}add
add(E e) 此方法会添加原数组就有的重复的元素 将指定元素追加到此列表的末尾。 public boolean add(E e) {final ReentrantLock lock this.lock;lock.lock();try {// 获取当前数组Object[] elements getArray();// 当前数组的长度int len elements.length;// copy 原数组的值到新数组中并设置新数组的容量是 原数组的容量 1 Object[] newElements Arrays.copyOf(elements, len 1);// 在新数组的最后位置添加这个元素newElements[len] e;// 新数组 变为 下次getArray 的数组setArray(newElements);return true;} finally {lock.unlock();}}
add(int index, E element) 此方法会添加原数组就有的重复的元素 在此列表中的指定位置插入指定元素。将当前位于该位置的元素如果有和任何后续元素向右移动将其索引加一 public void add(int index, E element) {final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;if (index len || index 0)throw new IndexOutOfBoundsException(Index: index, Size: len);Object[] newElements;// 需要移动的元素的个数int numMoved len - index;// 在末尾添加if (numMoved 0)//copy 原数组的值到新数组中并设置新数组的容量是 原数组的容量 1 newElements Arrays.copyOf(elements, len 1);// else {//设置新数组的容量是 原数组的容量 1 newElements new Object[len 1];// copy 原数组中 指定位置前 和指定位置 后的值到新数组中System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index, newElements, index 1,numMoved);}// 指定位置填充元素newElements[index] element;// 新数组 变为 下次getArray 的数组setArray(newElements);} finally {lock.unlock();}
}addAll(Collection? extends E c) 此方法会添加原数组就有的重复的元素 将指定集合中的所有元素按照指定集合的迭代器返回的顺序附加到此列表的末尾。 public boolean addAll(Collection? extends E c) {// 转为数组Object[] cs (c.getClass() CopyOnWriteArrayList.class) ?((CopyOnWriteArrayList?)c).getArray() : c.toArray();if (cs.length 0)return false;final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;// 要是原数组长度为 0 并且 添加的集合 是 CopyOnWriteArrayList 或者 ArrayListif (len 0 (c.getClass() CopyOnWriteArrayList.class || c.getClass() ArrayList.class)) {// 新增的集合就指定为 下次getArray 的数组 setArray(cs);} else {// copy 原数组的值到新数组中并设置新数组的容量是 原数组的容量 新增集合的长度Object[] newElements Arrays.copyOf(elements, len cs.length);// 将集合c 元素 copy 到末尾System.arraycopy(cs, 0, newElements, len, cs.length);// 新数组 变为 下次getArray 的数组setArray(newElements);}return true;} finally {lock.unlock();}
}addAll(int index, Collection? extends E c) 此方法会添加原数组就有的重复的元素 将指定集合中的所有元素插入到此列表中从指定位置开始。将当前位于该位置的元素如果有和任何后续元素向右移动增加它们的索引 public boolean addAll(int index, Collection? extends E c) {Object[] cs c.toArray();final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;if (index len || index 0)throw new IndexOutOfBoundsException(Index: index, Size: len);if (cs.length 0)return false;int numMoved len - index;Object[] newElements;// 不移动直接copy 到原来数组的末尾if (numMoved 0)newElements Arrays.copyOf(elements, len cs.length);else {// 指定位置之前和之后的元素拷贝到 新的副本中newElements new Object[len cs.length];System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index,newElements, index cs.length,numMoved);}// 在指定位置之后 填充集合元素System.arraycopy(cs, 0, newElements, index, cs.length);// // 新数组 变为 下次getArray 的数组setArray(newElements);return true;} finally {lock.unlock();}
}addAllAbsent(Collection? extends E c) 此方法不会添加原数组就有的重复的元素 将指定集合中尚未包含在此列表中的所有元素按照指定集合的迭代器返回的顺序追加到此列表的末尾。 public int addAllAbsent(Collection? extends E c) {Object[] cs c.toArray();// 创建一个cs的副本以防止对原始对象的修改影响到cs变量。if (c.getClass() ! ArrayList.class) {cs cs.clone();}if (cs.length 0)return 0;final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;int added 0; // 不重复元素的个数// uniquify and compact elements in csfor (int i 0; i cs.length; i) {Object e cs[i];// 原数组中 和 转为数组的集合中都没有这个元素 if (indexOf(e, elements, 0, len) 0 indexOf(e, cs, 0, added) 0)//将不重复的元素添加到 cs 数组中。cs[added] e;}if (added 0) {Object[] newElements Arrays.copyOf(elements, len added);//不重复元素放到新元素的末尾System.arraycopy(cs, 0, newElements, len, added);setArray(newElements);}// 返回原数组中不存在的集合中的元素的个数return added;} finally {lock.unlock();}
}
// 返回此列表中指定元素第一次出现的索引如果此列表不包含该元素则返回 -1。
// 更正式地说返回满足(onull ? get(i)null : o.equals(get(i))) 的最低索引i(第一个位置) 如果没有这样的索引则返回 -1 。// 遍历数组找到符合的元素找不到返回 -1private static int indexOf(Object o, Object[] elements,int index, int fence) {if (o null) {for (int i index; i fence; i)if (elements[i] null)return i;} else {for (int i index; i fence; i)if (o.equals(elements[i]))return i;}return -1;}
addIfAbsent(E e) 此方法不会添加原数组就有的重复的元素 追加该元素如果不存在。 public boolean addIfAbsent(E e) {Object[] snapshot getArray();// 要是元素在原来的数组中是存在的直接返回否则就调用 addIfAbsent(e, snapshot)return indexOf(e, snapshot, 0, snapshot.length) 0 ? false :addIfAbsent(e, snapshot);
}private boolean addIfAbsent(E e, Object[] snapshot) {final ReentrantLock lock this.lock;lock.lock();try {Object[] current getArray();int len current.length;// 要是数组发生了变化表示有其他线程正在竞争修改这个数组if (snapshot ! current) {// 得到两个数组的公共长度以小的值为准int common Math.min(snapshot.length, len);// 遍历两个数组的公共部分for (int i 0; i common; i)// 两个数组又不想等的元素 当前数组已经存在要添加的元素if (current[i] ! snapshot[i] eq(e, current[i]))// 不添加return false;// 遍历结束前面的部分都是一样的// 查找当前数组剩余部分的元素 要是此时能找到添加的元素也 不添加if (indexOf(e, current, common, len) 0)return false;}//否则创建当前数组的副本并在结尾加上这个元素Object[] newElements Arrays.copyOf(current, len 1);newElements[len] e;setArray(newElements);return true;} finally {lock.unlock();}}remove
remove(int index) 删除此列表中指定位置的元素。将所有后续元素向左移动从索引中减去 1。返回从列表中删除的元素。 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;// 不要移动 直接拷贝长度为原来数组的长度 -1if (numMoved 0)setArray(Arrays.copyOf(elements, len - 1));else {// 新建副本副本的长度减少为原来数组的长度 -1// 拷贝到新数组中该位置之前 和 该元素之后 的元素// 新数组 变为 下次getArray 的数组Object[] newElements new Object[len - 1];System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index 1, newElements, index,numMoved);setArray(newElements);}// 返回旧值return oldValue;} finally {lock.unlock();}}remove(Object o) 从此列表中删除第一次出现的指定元素如果存在。如果此列表不包含该元素则它不会更改。更正式地说删除具有最低索引i元素使得(onull ? get(i)null : o.equals(get(i))) 如果存在这样的元素。如果此列表包含指定的元素或者等效地如果此列表由于调用的结果而更改则返回true 。 public boolean remove(Object o) {Object[] snapshot getArray();// 判断原数组是否存在当前 元素并返回当前元素的位置int index indexOf(o, snapshot, 0, snapshot.length);// 存在才调用 remove(o, snapshot, index); 移除return (index 0) ? false : remove(o, snapshot, index);
}remove(Object o, Object[] snapshot, int index) 给定的最近快照在给定索引处包含 o。 private boolean remove(Object o, Object[] snapshot, int index) {final ReentrantLock lock this.lock;lock.lock();try {Object[] current getArray();int len current.length;// 数组发生了变化 if (snapshot ! current) findIndex: {// 取删除元素的下标和当前数组长度的最小值 进行 后续遍历int prefix Math.min(index, len);for (int i 0; i prefix; i) {// 数组中的元素出现了变化 并且 要删除的值就是当前位置的值if (current[i] ! snapshot[i] eq(o, current[i])) {// 更新要删除的元素的下标index i;// 结束循环break findIndex;}}// 要是现在的元素的下标已经超过要当前的数组的长度if (index len)// 删除失败return false;//上面两个数组公共位置的元素都是一样的那么现在就是当前index位置的元素判断是不是一样的 if (current[index] o)break findIndex; // 是就结束循环// 从index位置遍历现在数组的元素直到结束index indexOf(o, current, index, len);// 要是找不到删除失败if (index 0)return false;}// 新建副本副本的长度减少为原来数组的长度 -1// 拷贝到新数组中该位置之前 和 该元素之后 的元素// 新数组 变为 下次getArray 的数组Object[] newElements new Object[len - 1];System.arraycopy(current, 0, newElements, 0, index);System.arraycopy(current, index 1,newElements, index,len - index - 1);setArray(newElements);return true;} finally {lock.unlock();}}removeRange(int fromIndex, int toIndex) 从此列表中删除索引介于fromIndex 包含和toIndex 不包含之间的所有元素。将所有后续元素向左移动减少它们的索引。此调用将列表缩短(toIndex - fromIndex)个元素。 如果toIndexfromIndex 则此操作无效。 void removeRange(int fromIndex, int toIndex) {final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;if (fromIndex 0 || toIndex len || toIndex fromIndex)throw new IndexOutOfBoundsException();// 删除指定范围之后的数组长度int newlen len - (toIndex - fromIndex);// 需要移动的元素 int numMoved len - toIndex;// 不用移动直接拷贝之前的元素if (numMoved 0)setArray(Arrays.copyOf(elements, newlen));else {// 新建副本副本的长度减少为原来数组的长度 -1// 拷贝到新数组中该位置之前 和 该元素之后 的元素// 新数组 变为 下次getArray 的数组Object[] newElements new Object[newlen];System.arraycopy(elements, 0, newElements, 0, fromIndex);System.arraycopy(elements, toIndex, newElements,fromIndex, numMoved);setArray(newElements);}} finally {lock.unlock();}}removeAll(Collection? c) 从此列表中删除指定集合中包含的所有元素。由于需要内部临时数组因此在此类中这是一个特别昂贵的操作。 public boolean removeAll(Collection? c) {if (c null) throw new NullPointerException();final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;if (len ! 0) {// temp 数组保存需要保留的元素int newlen 0;Object[] temp new Object[len];// 遍历 原数组for (int i 0; i len; i) {Object element elements[i];// 要是删除元素的集合不包含这个元素塞到temp数组中if (!c.contains(element))temp[newlen] element;}// 有删除的元素if (newlen ! len) {// 将temp copy 作为新数组中setArray(Arrays.copyOf(temp, newlen));return true;}}return false;} finally {lock.unlock();}}removeIf(Predicate? super E filter) 根据指定条件过滤集合元素的功能 public boolean removeIf(Predicate? super E filter) { //Predicate? super E 类型的参数 filter用于过滤集合中的元素if (filter null) throw new NullPointerException();final ReentrantLock lock this.lock;lock.lock();try {Object[] elements getArray();int len elements.length;if (len ! 0) {int newlen 0;Object[] temp new Object[len];//遍历现在的数组如果元素不满足 filter 的条件则将其保存在 temp 数组中并增加 newlen 的值。for (int i 0; i len; i) {SuppressWarnings(unchecked) E e (E) elements[i];if (!filter.test(e))temp[newlen] e;}//有元素被删除if (newlen ! len) {// 将temp copy 作为新数组中setArray(Arrays.copyOf(temp, newlen));return true;}}return false;} finally {lock.unlock();}
}clear 从此列表中删除所有元素。该调用返回后列表将为空。 public void clear() {final ReentrantLock lock this.lock;lock.lock();try {// 设置一个空的数组作为新的数组setArray(new Object[0]);} finally {lock.unlock();}
}