zoukankan      html  css  js  c++  java
  • Java 原子类 java.util.concurrent.atomic

    Java 原子类 java.util.concurrent.atomic

    1、i++为什么是非线程安全的

    i++其实是分为3个步骤:获取i的值, 把i+1, 把i+1的结果赋给i

    如果多线程执行i++操作,没有同步的话,结果可能不正确

    如两个线程同时获取i的值,然后各自+1后,赋给i。正确的情况下i的值应该是加了2,但这里其实加了1而且,前面的结果被覆盖了。

    通常做法:synchronized (synchronized方法,synchronized变量), 但这样做效率不是最优的。

    2、AtomicInteger的实现

    主要依靠:1、volatile 保证了变量的可见性,所有线程不缓存volatile变量,需要时都从内存读取,这样能保证所有数据拿到的值都是最新的。

    2、compareAndSet(int expect, int update)判断当前值==expect?当前值=update:错误;

    这里做了两步操作,判断跟赋值。但因为cpu提供这样指令的支持,所有能保证这个操作时原子的。

    Java代码 复制代码 收藏代码
    1. public class AtomicIntegerextends Number implements java.io.Serializable {
    2. private staticfinal long serialVersionUID = 6214790243416807050L;
    3. // setup to use Unsafe.compareAndSwapInt for updates
    4. private staticfinal Unsafe unsafe = Unsafe.getUnsafe();
    5. private staticfinal long valueOffset;
    6. static {
    7. try {
    8. valueOffset = unsafe.objectFieldOffset
    9. (AtomicInteger.class.getDeclaredField("value"));
    10. } catch (Exception ex) { throw new Error(ex); }
    11. }
    12. private volatileint value;
    public class AtomicInteger extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        // setup to use Unsafe.compareAndSwapInt for updates
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long valueOffset;
    
        static {
          try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
          } catch (Exception ex) { throw new Error(ex); }
        }
    
        private volatile int value;

    3、AtomicInteger 中的set(int newValue) lazySet(int newValue)

    void set(int newValue)

    设置为给定值。 直接修改原始值,也就是i=newValue操作。

    void lazySet(int newValue) 最后设置为给定值。

    延时设置变量值,这个等价于set()方法,但是由于字段是volatile类型的,因此次字段的修改会比普通字段(非volatile字段)有稍微的性能延时(尽管可以忽略),所以如果不是想立即读取设置的新值,允许在“后台”修改值,那么此方法就很有用。如果还是难以理解,这里就类似于启动一个后台线程如执行修改新值的任务,原线程就不等待修改结果立即返回(这种解释其实是不正确的,但是可以这么理解)。



    4、AtomicInteger中compareAndSet(int expect, int update) weakCompareAndSet(int expect, int update)

    boolean weakCompareAndSet(int expect, int update)
    如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。JSR规范中说:以原子方式读取和有条件地写入变量但 创建任何 happen-before 排序,因此不提供与除weakCompareAndSet 目标外任何变量以前或后续读取或写入操作有关的任何保证。大意就是说调用weakCompareAndSet时并不能保证不存在happen-before的发生(也就是可能存在指令重排序导致此操作失败)。但是从Java源码来看,其实此方法并没有实现JSR规范的要求,最后效果和compareAndSet是等效的,都调用了unsafe.compareAndSwapInt()完成操作。

    Java代码 复制代码 收藏代码
    1. /**
    2. * Atomically sets the value to the given updated value
    3. * if the current value {@code ==} the expected value.
    4. *
    5. * @param expect the expected value
    6. * @param update the new value
    7. * @return true if successful. False return indicates that
    8. * the actual value was not equal to the expected value.
    9. */
    10. public finalboolean compareAndSet(int expect,int update) {
    11. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    12. }
    13. /**
    14. * Atomically sets the value to the given updated value
    15. * if the current value {@code ==} the expected value.
    16. *
    17. * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
    18. * and does not provide ordering guarantees, so is only rarely an
    19. * appropriate alternative to {@code compareAndSet}.
    20. *
    21. * @param expect the expected value
    22. * @param update the new value
    23. * @return true if successful.
    24. */
    25. public finalboolean weakCompareAndSet(int expect,int update) {
    26. return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    27. }
        /**
         * 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(int expect, int update) {
    	return unsafe.compareAndSwapInt(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(int expect, int update) {
    	return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    
  • 相关阅读:
    记录PHP的执行时间
    Mysql数据字典导出
    PHP用post来进行Soap请求
    laravel(lumen)配置读写分离后,强制读主(写)库数据库,解决主从延迟问题
    使用vagrant构建你们团队的开发环境
    Lumen框架使用Redis与框架Cache压测比较
    使用php-cs-fixer格式化你的代码
    Javascript下拉导航
    jsf2.0视频
    jsf2入门视频 教程
  • 原文地址:https://www.cnblogs.com/yangkai-cn/p/4017239.html
Copyright © 2011-2022 走看看