上文中,guava代码中就用到了,在这里再专门捋一下
部分内容源自:
https://www.jianshu.com/p/712681f5aecd
https://www.yiibai.com/java_concurrency/concurrency_atomiclong.html
AtomicReferenceArray<ReferenceEntry<K, V>>
根据变量类型的不同,Atomic包中的这12个原子操作类可以分为4种类型:
①原子更新基本类型:
②原子更新数组:
③原子更新引用:
④原子更新字段(属性):
它们都是使用Unsafe实现的包装类。
①原子更新基本类型:
AtomicBoolean、AtomicInteger、AtomicLong
②原子更新数组:
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
③原子更新引用:
AtomicReference、AtomicReferenceFiledUpdater、AtomicMarkableReference
④原子更新字段(属性):
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference
它们都是使用Unsafe实现的包装类。
对于原子更新类基本操作,可以看到AtomicInteger中基本有以下一些方法,其他也都差不多,用法简单
Executor executor = Executors.newFixedThreadPool(3); AtomicInteger atomicInteger = new AtomicInteger(0); for(int i = 0; i < 10; i++){ executor.execute(()->{ System.out.println("atomicInteger的当前值:" + atomicInteger.addAndGet(1)); }); }
原子更新数组,例AtomicReferenceArray,用法抄自上文,实际就是基于cas的操作
public class MainTest { private static String[] source = new String[10]; private static AtomicReferenceArray<String> atomicReferenceArray = new AtomicReferenceArray<String>(source); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < atomicReferenceArray.length(); i++) { atomicReferenceArray.set(i, "item-2"); } Thread t1 = new Thread(new Increment()); Thread t2 = new Thread(new Compare()); t1.start(); t2.start(); t1.join(); t2.join(); } static class Increment implements Runnable { public void run() { for (int i = 0; i < atomicReferenceArray.length(); i++) { String add = atomicReferenceArray.getAndSet(i, "item-" + (i + 1)); System.out.println("Thread " + Thread.currentThread().getId() + ", index " + i + ", value: " + add); } } } static class Compare implements Runnable { public void run() { for (int i = 0; i < atomicReferenceArray.length(); i++) { System.out.println("Thread " + Thread.currentThread().getId() + ", index " + i + ", value: " + atomicReferenceArray.get(i)); boolean swapped = atomicReferenceArray.compareAndSet(i, "item-2", "updated-item-2"); System.out.println("Item swapped: " + swapped); if (swapped) { System.out .println("Thread " + Thread.currentThread().getId() + ", index " + i + ", updated-item-2"); } } } } }
AtomicReferenceFiledUpdater https://github.com/aCoder2013/blog/issues/10 这个blog写的真不错,在jdk中有很多应用。比如对buf的更新等
一个基于反射的工具类,它能对指定类的指定的volatile引用字段进行原子更新。(注意这个字段不能是private的)
class Node { private volatile Node left, right; private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); Node getLeft() { return left; } boolean compareAndSetLeft(Node expect, Node update) { return leftUpdater.compareAndSet(this, expect, update); } // ... and so on }}
public class BufferedInputStream extends FilterInputStream { protected volatile byte buf[]; /* * 原子的更新内部数组,比如扩容、关闭时, */ private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater.newUpdater (BufferedInputStream.class, byte[].class, "buf"); public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { //放在一个循环中,如果CAS更新失败,那么就读取最新的buf引用,继续CAS更新 if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; } } } }
AtomicStampedReference 通过包装[E,Integer]的元组来对对象标记版本戳stamp,从而避免ABA问题