首页 / JAVA / java并发编程之美-阅读记录5
java并发编程之美-阅读记录5
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了java并发编程之美-阅读记录5,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6163字,纯文字阅读大概需要9分钟。
内容图文
java并发包中的并发List
5.1CopeOnWriteArrayList
并发包中的并发List只有CopyOnWriteArrayList,该类是一个线程安全的arraylist,对其进行的修改操作都是在底层的一个复制数组上进行的,也就是使用了写时复制策略。
该类的结构:
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { privatestaticfinallong serialVersionUID = 8673264195747942595L; // 可重入的独占锁,用来保证对arraylist的修改操作,同一时间只有一个线程finaltransient ReentrantLock lock = new ReentrantLock(); // 存放对象的底层数组 内存可见性privatetransientvolatile Object[] array; // 基于硬件的原子操作了Unsafeprivatestaticfinal sun.misc.Unsafe UNSAFE; // 锁的偏移量privatestaticfinallong lockOffset; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> k = CopyOnWriteArrayList.class; lockOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("lock")); } catch (Exception e) { thrownew Error(e); } } }
问题:
何时初始化list,初始化list的大小是多少,list是有限大小吗? copyonwriteArraylist是无界数组
如何保证线程安全,比如多个线程进行读写时如何保证是线程安全的?
如何保证迭代器遍历list时的数据一致性?
5.2源码分析
1、初始化
构造函数:
// 空的list public CopyOnWriteArrayList() { setArray( new Object[0]); } // 入参为Collection类型的集合,该构造会将集合中的元素复制到list中 public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements; if (c.getClass() == CopyOnWriteArrayList.class) elements = ((CopyOnWriteArrayList<?>)c).getArray(); else { elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652)if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); } setArray(elements); } // 入参为泛型数组,将数组复制到list的底层数组中 public CopyOnWriteArrayList(E[] toCopyIn) { setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class)); }
2、添加元素add方法
// 添加元素,在list的末尾添加 public boolean add(E e) { final ReentrantLock lock = this.lock;
// 获取独占锁 lock.lock(); try {
// 获取copyOnWriteArrayList底层数组 Object[] elements = getArray(); int len = elements.length;
// 复制一份新的数组,比原数组大一,所以CopyOnWriteArraylist是一个无界数组 Object[] newElements = Arrays.copyOf(elements, len + 1);
// 将要添加的元素放到新数组的最后位置 newElements[len] = e;
// 使用新数组替换原来的数组 setArray(newElements); returntrue; } finally {
// 操作完毕后,释放独占锁 lock.unlock(); } }
3、获取元素,此时就会产生写时复制的弱一致性问题:当线程a获取到地层数组后,但是没有执行get(Object[] a,int index)方法,此时线程b操作该集合,删除了一个元素(删除的是复制出的新数组中的数据,同时会使用新数组覆盖旧数组),name线程a继续获取执行位置的数据,此时底层数组仍然是之前没有删除数据的数组,这样就产生了弱一致性问题。
// 直接获取底层数组指定索引位置的数据 private E get(Object[] a, int index) { return (E) a[index]; } // 获取指定索引出的值 getArray方法返回底层数组public E get(int index) { return get(getArray(), index); }
4、修改指定位置的元素
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; Object[] newElements = Arrays.copyOf(elements, len); newElements[index] = element; setArray(newElements); } else { // Not quite a no-op; ensures volatile write semantics // 旧数组重新覆盖旧数组--> 这一步虽然没有改变数组,但是为了保证volatitle语义,仍然会重新设置一次 setArray(elements); } return oldValue; } finally { // 释放锁 lock.unlock(); } }
5、删除元素
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; // 要移动的元素为0,则代表删除的是最后一个元素if (numMoved == 0) setArray(Arrays.copyOf(elements, len - 1)); else { // 要删除的不是最后一个,则新建一个len-1长度的数组 Object[] newElements = new Object[len - 1]; // 同时以要删除的索引index为分界线,复制0-index,index+1 - len的元素 System.arraycopy(elements, 0, newElements, 0, index); System.arraycopy(elements, index + 1, newElements, index, numMoved); setArray(newElements); } return oldValue; } finally { lock.unlock(); } }
6、弱一致性的迭代器
所谓弱一致性是指:返回迭代器后,其他线程对list的操作(增删改)对迭代器是不可见的。
public Iterator<E> iterator() { returnnew COWIterator<E>(getArray(), 0); } // 可以看到迭代器中的方法,不能增删改,相应的方法会抛出异常staticfinalclass COWIterator<E> implements ListIterator<E> { /** Snapshot of the array */privatefinal Object[] snapshot; /** Index of element to be returned by subsequent call to next. */privateint cursor; private COWIterator(Object[] elements, int initialCursor) { cursor = initialCursor; snapshot = elements; } publicboolean hasNext() { return cursor < snapshot.length; } publicboolean hasPrevious() { return cursor > 0; } @SuppressWarnings("unchecked") public E next() { if (! hasNext()) thrownew NoSuchElementException(); return (E) snapshot[cursor++]; } @SuppressWarnings("unchecked") public E previous() { if (! hasPrevious()) thrownew NoSuchElementException(); return (E) snapshot[--cursor]; } publicint nextIndex() { return cursor; } publicint previousIndex() { return cursor-1; } publicvoid remove() { thrownew UnsupportedOperationException(); } publicvoid set(E e) { thrownew UnsupportedOperationException(); } publicvoid add(E e) { thrownew UnsupportedOperationException(); } @Override publicvoid forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); Object[] elements = snapshot; finalint size = elements.length; for (int i = cursor; i < size; i++) { @SuppressWarnings("unchecked") E e = (E) elements[i]; action.accept(e); } cursor = size; } }
弱一致性:
package com.nxz.blog.otherTest; import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList; public class TestThread003 { private static CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>(); /** * 测试CopyOnWriteArrayList的弱一致性问题 * 如果输出结果是:test1 test2 test3 test4 则说明该类具有弱一致性
*/publicstaticvoid main(String[] args) throws InterruptedException { copyOnWriteArrayList.add("test1"); copyOnWriteArrayList.add("test2"); copyOnWriteArrayList.add("test3"); copyOnWriteArrayList.add("test4"); Thread t = new Thread(new Runnable() { @Override publicvoid run() { copyOnWriteArrayList.add("runnabl1"); copyOnWriteArrayList.add("runnabl2"); copyOnWriteArrayList.add("runnabl3"); } }); Iterator<String> iterator = copyOnWriteArrayList.iterator(); // 等待线程执行完毕 t.join(); while (iterator.hasNext()) { System.out.println(iterator.next()); } } }
结果:
test1
test2
test3
test4
原文:https://www.cnblogs.com/nxzblogs/p/11332231.html
内容总结
以上是互联网集市为您收集整理的java并发编程之美-阅读记录5全部内容,希望文章能够帮你解决java并发编程之美-阅读记录5所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。