it_worker365

   ::  ::  ::  ::  :: 管理

上文中,guava代码中就用到了,在这里再专门捋一下

部分内容源自:

https://www.jianshu.com/p/712681f5aecd

https://www.yiibai.com/java_concurrency/concurrency_atomiclong.html

AtomicReferenceArray<ReferenceEntry<K, V>>
根据变量类型的不同,Atomic包中的这12个原子操作类可以分为4种类型:
①原子更新基本类型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问题

 

posted on 2018-11-13 11:27  it_worker365  阅读(163)  评论(0编辑  收藏  举报