您的位置:首页 > 游戏 > 手游 > 建立自己的网站平台的好处_网络营销方式对比_广东深圳疫情最新情况_深圳疫情最新情况

建立自己的网站平台的好处_网络营销方式对比_广东深圳疫情最新情况_深圳疫情最新情况

2025/7/6 7:54:39 来源:https://blog.csdn.net/liiilbb/article/details/144095190  浏览:    关键词:建立自己的网站平台的好处_网络营销方式对比_广东深圳疫情最新情况_深圳疫情最新情况
建立自己的网站平台的好处_网络营销方式对比_广东深圳疫情最新情况_深圳疫情最新情况

目录

5.1 介绍

5.2 主要方法源码解析

初始化 

5.2.2 添加元素 

5.2.3 获取指定位置元素 

5.2.4 修改指定元素 

5.2.5 删除元素

5.2.6 弱一致性的迭代器 


5.1 介绍

  1. 并发包中的并发 List 只有 CopyOnWriteArrayList。CopyOnWriteArrayList 是一个线程安全的 ArrayList,对其进行的修改操作都是在底层的一个复制的数组(快照)上进行的,也就是使用了写时复制策略,用来保证 list 的一致性,
  2. 但是获取—修改—写 入三步操作并不是原子性的,所以在增删改的过程中都使用了独占锁ReentrantLock,来保证在某个时间只有一个线程能对 list 数组进行修改。
  3. 但是在“获取指定位置元素”时没有加锁同步,所以 CopyOnWriteArrayList 提供了弱一致性的迭代器,从而保证在获取迭代器后,其他线程对 list 的修改是不可见的。

5.2 主要方法源码解析

初始化 

//无参构造函数,在内部创建了一个大小为 0 的 Object 数组作为
//array 的初始值。public CopyOnWriteArrayList() {setArray(new Object[0]);}//有参构造函数。
//创建一个list,其内部元素是入参toCopyIn的副本public CopyOnWriteArrayList(E[] toCopyIn) {setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));}//入参为集合,将集合里面的元素复制到本listpublic CopyOnWriteArrayList(Collection<? extends E> c) {Object[] elements;if (c.getClass() == CopyOnWriteArrayList.class)elements = ((CopyOnWriteArrayList<?>)c).getArray();else {elements = c.toArray();if (elements.getClass() != Object[].class)elements = Arrays.copyOf(elements, elements.length, Object[].class);}setArray(elements);}

5.2.2 添加元素 

CopyOnWriteArrayList 中用来添加元素的函数有 add(E e) , add(int index, E element),
addIfAbsent(E e) addAllAbsent(Collection<? extends E> c) 等。
public boolean add(E e) {//获取独占锁(1)final ReentrantLock lock = this.lock;lock.lock();try {//(2)获取arrayObject[] elements = getArray();//(3)复制array到新数组,添加元素到新数组int len = elements.length;
//从这里可以知道新数组的大小是原来数组大小增加 1,所以 CopyOnWriteArrayList 是无界 list)Object[] newElements = Arrays.copyOf(elements, len + 1);
//把新增的元素E e添加到新数组。newElements[len] = e;//(4)使用新数组替换添加前的数组setArray(newElements);return true;} finally {//(5)释放独占锁lock.unlock();}
} 
由于加了锁,所以整个 add 过程是个原子性操作。需要注意的是,在添加元素时,首先 复制了一个快照 ,然 后在快照上进行添加,而不是直接在原来数组上进行。

5.2.3 获取指定位置元素 

使用 E get(int index) 获取下标为 index 的元素,如果元素不存在则抛出IndexOutOfBoundsException 异常。
public E get(int index) {
//(1)先获取array 数组
return get(getArray(), index);
}final Object[] getArray() {
return array;
}//(2)通过下标访问指定位置的元素
private E get(Object[] a, int index) {
return (E) a[index];
}

这个过程没有加锁同步,会出现一些问题,以下具体分析:

由于执行步骤 A(获取array 数组 ) 和步骤 B (通过下标访问指定位置的元素)没有加锁,这就可能导致在线程 x 执行完步骤 A 后执行步骤 B 前,另外一个线程 y 进行了 remove 操作,线程y结束后, 这时线程 x 开始执行步骤 B ,步骤 B 操作的数组是线程 y 删除元素之前的数组,
所以,虽然线程 y 已经删除了 index 处的元素,但是线程 x 的步骤 B 还是会返回
index 处的元素,这其实就是 写时复制策略 产生的 弱一致性问题

5.2.4 修改指定元素 

使用 E setint index,E element 修改 list 中指定元素的值,如果指定位置的元素不存在则抛出 IndexOutOfBoundsException 异常
public E set(int index, E element) {
//获取了独占锁,从而阻止其他线程对 array 数组进行修改final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();
//调用 get 方法获取指定位置的元素E oldValue = get(elements, index);//如果指定位置的元素值与新值不一致则创建新数组并复制元素,
//然后在新数组上修改指定位置的元素值并设置新数组到 array。if (oldValue != element) {int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len);newElements[index] = element;setArray(newElements);} else {//为了保证 volatile 语义,还是需要重新设置 array,setArray(elements);}return oldValue;} finally {lock.unlock();}
}

5.2.5 删除元素

删除 list 里面指定的元素 , 可以使用 E remove(int index) boolean remove(Object o)
boolean remove(Object o, Object[] snapshot, int index) 等方法
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;//如果要删除的是最后一个元素if (numMoved == 0)setArray(Arrays.copyOf(elements, len - 1));else {//分两次复制删除后剩余的元素到新数组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();}}

首先获取独占锁以保证删除数据期间其他线程不能对 array 进行修改,然后获取数组中要被删除的元素,并把剩余的元素复制到新数组之后使用新数组替换原来的数组,最后在返回前释放锁。

5.2.6 弱一致性的迭代器 

迭代器使用:遍历列表元素。

{CopyOnWriteArrayList<String> arrayList = new CopyOnWriteArrayList<>();arrayList.add("hello");arrayList.add("alibaba");Iterator<String> itr = arrayList.iterator();while(itr.hasNext()){System.out.println(itr.next());}
}
弱一致性 是指返回迭代器后其他线程对 list 的增删改迭代器是不可见的。
也就是说,如果在线程1中我最先获取了迭代器,线程2,3对数组元素进行增删改,然后执行完线程2,3后,线程1用获得的迭代器遍历数组,遍历的结果和初始数组一样,迭代器不会管(不可见)线程2,3对数组的更新后的新数组。
public Iterator<E> iterator() {return new COWIterator<E>(getArray(), 0);
}
static final class COWIterator<E> implements ListIterator<E> {//array的快照版本private final Object[] snapshot;//数组下标private int cursor;//构造函数private COWIterator(Object[] elements, int initialCursor) {cursor = initialCursor;snapshot = elements;}//是否遍历结束public boolean hasNext() {return cursor < snapshot.length;}//获取元素public E next() {if (! hasNext())throw new NoSuchElementException();return (E) snapshot[cursor++];}
为什么说 snapshot list 的快照呢?
明明是指针传递的引用,而不是副本。那是因为如果在该线程使用返回的迭代器遍历元素的过程中,其他线程没有对 list 进行增删改,那么 snapshot 本身就是 list array ,因为它们是引用关系。但是如果在遍历期间其他线程对该 list进行了增删改,那么 snapshot 就是快照了,因为增删改后 list 里面的数组被新数组替换了, 这时候老数组被 snapshot 引用。这也说明获取迭代器后,使用该迭代器元素时,其他线程对该 list 进行的增删改不可见,因为它们操作的是两个不同的数组,这就是弱一致性。所以说, 迭代器遍历的数组是一个快照
下面通过一个例子来演示多线程下迭代器的弱一致性的效果。可以自己运行查看结果
public class copylist
{
private static volatile CopyOnWriteArrayList<String> arrayList = new
CopyOnWriteArrayList<>();
public static void main( String[] args ) throws InterruptedException
{
arrayList.add("hello");
arrayList.add("alibaba");
arrayList.add("welcome");
arrayList.add("to");
arrayList.add("hangzhou");Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {//修改list中下标为1的元素为baba
arrayList.set(1, "baba");
//删除元素
arrayList.remove(2);
arrayList.remove(3);
}
});//保证在修改线程启动前获取迭代器
Iterator<String> itr = arrayList.iterator();
//启动线程
threadOne.start();//等待子线程执行完毕
threadOne.join();//迭代元素
while(itr.hasNext()){
System.out.println(itr.next());
}
}
}

主线程在子线程执行完毕后使用获取的迭代器遍历数组元素,从输出结果我们知道,在子线程里面进行的操作一个都没有生效,这就是迭代器弱一致性的体现。获取迭代器的操作必须在子线程操作之前进行。

                                                 CHAPTER-FIVE  OVER.......

                                                            PROCESS--->5/11

                ​​​​​​​        ​​​​​​​        

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com