zoukankan      html  css  js  c++  java
  • java并发J.U.C AtomicReference VS Volatile

    SpinLock实现,摘自并发编程网

    package com.juc.simple;
    
    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * a implement of spinlock based on  cas
     *
     */
    public class SpinLock {
    	private AtomicReference<Thread> sign = new AtomicReference<>();
    	/**
    	 * 让当前线程不停地的在循环体内执
    	 * 当循环的条件被其他线程改变时 才能进入临界区
    	 */
    	public void lock() {
    		Thread current = Thread.currentThread();
    		//自旋,如果sign为null才能设置为current or memcachedb: checkandset
    		while (!sign.compareAndSet(null, current)) {
    		}
    	}
    
    	public void unlock() {
    		Thread current = Thread.currentThread();
    		sign.compareAndSet(current, null);
    	}
    }
    

    这里是通过 AtomicReference实现的,而AtomicReference是通过volatile与Unsafe的CAS实现

    volatile保证可见性,所有的线程看到的都是最新(主内存?)的值,但是volatile的操作不具有原子性,这样像(a++)这种操作就不能保证安全了,实际是读--修改--写操作的过程

    AtomicReference的CAS操作更新值具有原子性

    先来一段AtomicReference与volatile的比较

    package com.juc.simple;
    
    import java.util.concurrent.atomic.AtomicReference;
    
    public class VolatileVsAtomicReference {
    	
    	private static volatile Integer volatileVar = 0;
    	//初始值value为0
    	private static AtomicReference<Integer> atomicReference=new AtomicReference<Integer>(volatileVar);
    	
    	public static void main(String[] args) {
    		
    		 try {
    			testAtomicReference();
    			testVolatile();
    		} catch (InterruptedException e) {
    			System.out.println(e.getMessage());
    		}
    	}
    	public static void testAtomicReference() throws InterruptedException{
    	    for (int i = 0; i < 1000; i++) {
    	        new Thread(new Runnable(){
    	            @Override
    	            public void run() {
    	                for (int i = 0; i < 1000; i++)
    	                    while(true){
    	                        Integer temp=atomicReference.get();
    	                        if(atomicReference.compareAndSet(temp, temp+1)){
    	                        	break;
    	                        }
    	                    }
    	            }       
    	        }).start();
    	    }
    	    Thread.sleep(1000);
    	    System.out.println("atomicReference "+atomicReference.get()); //1000000
    	}
    	    
    	public static void testVolatile() throws InterruptedException{
    	    for (int i = 0; i < 1000; i++) {
    	        new Thread(new Runnable(){
    	            @Override
    	            public void run() {
    	                for (int i = 0; i < 1000; i++) {
    	                	volatileVar=volatileVar++;
    	                }
    	            }       
    	        }).start();
    	    }
    	    Thread.sleep(1000);
    	    System.out.println("volatileVar "+volatileVar); //may 8545
    	}
    
    }
    

    结果:试过好几次volatileVar值都是不一样的

    atomicReference 1000000
    volatileVar 8545
    

    这里可以看出如果用了CAS的话AtomicReference是可以保证原子性的,但如果只是简单的get()和set()方法是不行的,其实就等同于volatile,因为这货本身就是volatile实现的

    参考

    Java volatile reference vs. AtomicReference

    oracle官方链接地址

    get has the memory effects of reading a volatile variable.
    set has the memory effects of writing (assigning) a volatile variable.
    

    Java 理论与实践: 正确使用 Volatile 变量

    AtomicReference的原代码实现

    package java.util.concurrent.atomic;
    import sun.misc.Unsafe;
    
    /**
     * An object reference that may be updated atomically. See the {@link
     * java.util.concurrent.atomic} package specification for description
     * of the properties of atomic variables.
     * @since 1.5
     * @author Doug Lea
     * @param <V> The type of object referred to by this reference
     */
    public class AtomicReference<V>  implements java.io.Serializable {
        private static final long serialVersionUID = -1848883965231344442L;
    
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long valueOffset;
    
        static {
          try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicReference.class.getDeclaredField("value"));
          } catch (Exception ex) { throw new Error(ex); }
        }
        //volatile 变量
        private volatile V value;
    
        /**
         * Creates a new AtomicReference with the given initial value.
         *
         * @param initialValue the initial value
         */
        public AtomicReference(V initialValue) {
            value = initialValue;
        }
    
        /**
         * Creates a new AtomicReference with null initial value.
         */
        public AtomicReference() {
        }
    
        /**
         * Gets the current value.
         *
         * @return the current value
         */
        public final V get() {
            return value;
        }
    
        /**
         * Sets to the given value.
         *
         * @param newValue the new value
         */
        //volatile变量赋值
        public final void set(V newValue) {
            value = newValue;
        }
    
        /**
         * Eventually sets to the given value.
         *
         * @param newValue the new value
         * @since 1.6
         */
        //设置为新的值
        public final void lazySet(V newValue) {
            unsafe.putOrderedObject(this, valueOffset, newValue);
        }
    
        /**
         * Atomically sets the value to the given updated value
         * if the current value {@code ==} the expected value.
         * @param expect the expected value
         * @param update the new value
         * @return true if successful. False return indicates that
         * the actual value was not equal to the expected value.
         */
        //如果当前值与期望值一致,则设置为新的值
        public final boolean compareAndSet(V expect, V update) {
            return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
        }
    
        /**
         * Atomically sets the value to the given updated value
         * if the current value {@code ==} the expected value.
         *
         * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
         * and does not provide ordering guarantees, so is only rarely an
         * appropriate alternative to {@code compareAndSet}.
         *
         * @param expect the expected value
         * @param update the new value
         * @return true if successful.
         */
        public final boolean weakCompareAndSet(V expect, V update) {
            return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
        }
    
        /**
         * Atomically sets to the given value and returns the old value.
         *
         * @param newValue the new value
         * @return the previous value
         */
        //以原子方式设置为新的值,并且返回旧值
        public final V getAndSet(V newValue) {
            while (true) {
                V x = get();
                if (compareAndSet(x, newValue))
                    return x;
            }
        }
    
        /**
         * Returns the String representation of the current value.
         * @return the String representation of the current value.
         */
        public String toString() {
            return String.valueOf(get());
        }
    
    }
    
  • 相关阅读:
    u盘的超级用法
    文件夹访问被拒绝
    web移动前端的click点透问题
    call()apply()ind()备忘录
    Safari中的new Date()格式化坑
    dataURI V.S. CSS Sprites 移动端
    css3属性之 box-sizing
    多人协作代码--公共库的引用与业务约定
    web前端本地测试方法
    依赖包拼合方法
  • 原文地址:https://www.cnblogs.com/donganwangshi/p/4234160.html
Copyright © 2011-2022 走看看