• 天涯煮酒
    2019-04-16
    or = rf.get(); 应该放到do{}内
    
     31
  • 张天屹
    2019-04-16
    如果线程1 运行到WMRange or = rf.get();停止,切换到线程2 更新了值,切换回到线程1,进入循环将永远比较失败死循环,解决方案是将读取的那一句放入循环里,CAS每次自旋必须要重新检查新的值才有意义

    作者回复: 👍

    
     19
  • Geek_ebda96
    2019-04-18
    老师你举的这个例子,自己实现CAS是不是有点不对
    class SimulatedCAS{
      volatile int count;
      // 实现 count+=1
      addOne(){
        do {
          newValue = count+1; //①
        }while(count !=
          cas(count,newValue) //②
      }
      // 模拟实现 CAS,仅用来帮助理解
      synchronized int cas(
        int expect, int newValue){
        // 读目前 count 的值
        int curValue = count;
        // 比较目前 count 值是否 == 期望值
        if(curValue == expect){
          // 如果是,则更新 count 的值
          count= newValue;
        }
        // 返回写入前的值
        return curValue;
      }
    }

    2 这里是不是应该用oldValue来比较,在do里面的时候先把count的值用oldValue保存下来,传入的参数expected为oldValue,newValue为oldValue+1

    do{
        oldValue = count;
        newValue = oldValue + 1;
    }while(oldValue != cas(oldValue, newValue))

    望指正
    展开

    作者回复: 你的这个写法是对的👍

     5
     15
  • 郑晨Cc
    2019-04-16
    or是原始的 nr是new出来的 指向不同的内存地址 compareandset的结果永远返回false 结果是死循环?是不是应该用atomicfieldreference?

    作者回复: 👍,不过我觉得没必要用atomicfieldreference

     1
     10
  • andy
    2019-04-16
    public class SafeWM {
      class WMRange{
        final int upper;
        final int lower;
        WMRange(int upper,int lower){
        // 省略构造函数实现
        }
      }
      final AtomicReference<WMRange>
        rf = new AtomicReference<>(
          new WMRange(0,0)
        );
      // 设置库存上限
      void setUpper(int v){
        WMRange nr;
        WMRange or;
        do{
         or = rf.get();
          // 检查参数合法性
          if(v < or.lower){
            throw new IllegalArgumentException();
          }
          nr = new
            WMRange(v, or.lower);
        }while(!rf.compareAndSet(or, nr));
      }
    }

     这样子对吗?
    展开

    作者回复: 对👍

     2
     8
  • 榣山樵客™
    2019-04-16
    首先,or=rf.get()需要放到do{},每次需要重新获取,以防其他线程更新过导致死循环;

    然后,nr是new的,我觉得应该不会发生ABA的问题(reference的compareAndSet比较的是内存地址)。另外ABA问题应该容易发生在值类型上吧,引用类型的应该几乎不会发生?对于引用类型,几乎不会发生经过至少两次new对象,最后对象放在了同一块or之前使用的内存区块上吧?

    作者回复: 我也觉得没有ABA问题

    
     6
  • 刘志兵
    2019-04-17
    老师,compareAndSwapLong方法是一个native方法,比较共享变量和expect值是否相等,相等才设置新的值x, 不明白这里的对比是怎么保证原子性的,对比也是要再读一次共享变量,然后对比吧,如果先读出来之后对比的时候被其他线程修改了,那还是会有问题

    作者回复: 最终依赖的是cpu提供的原子指令,不用我们操心。

    
     4
  • 密码123456
    2019-04-16
    我觉得可能会出现死循环。WMRange or = rf.get(); 应该放在do里面。每次比较交换失败后,重新获取一次。

    作者回复: 👍

    
     4
  • 刘育飞
    2019-10-17
    不明白 synchronized int cas() 这不是已经用了 同步synchronized 关键字 吗怎么会 无锁 无堵塞呢

    作者回复: cas大部分都是CPU提供的指令,这里只是模拟它的原理

    
     3
  • Vincent
    2019-06-25
    第一个例子也不是线程安全的吧?i++这个操作不是线程安全的,会导致判断错误吧?

    作者回复: 局部变量不存在线程安全问题

    
     3
  • xuery
    2019-05-02
    例子中的模拟CAS,cas函数是加了锁的,保证整个操作的原子性;我的理解是这个只是一个模拟,实际中肯定不会加上锁的

    作者回复: 👍

    
     3
  • Sean
    2019-05-24
    设置上限为什么是WMRange(v, or.lower);? 是笔误还是我理解错了?

    作者回复: v是上限,下限不变,没问题

    
     2
  • 东风第一枝
    2019-11-18
    // 比较目前count值是否==期望值
    if(curValue == expect){
    // 如果是,则更新count的值
    count= newValue;
    }
    ==========
    这段代码老师说是仅用来帮助理解,实际上这个是存在竞态条件的,如果在if执行完之后,count的值被别的变量修改,那么结果就不正确了。想找老师确认一下我理解的对不对?
    展开

    作者回复: 这段代码所在的方法是synchronized😂

    
     1
  • 随心而至
    2019-09-05
    感觉理解好了volatile和CAS,这些原子类就都好理解了

    作者回复: 👍

    
     1
  • 赤城
    2019-05-16
    cas的实现原理感觉跟乐观锁有相似的地方,不知道是不是可以这么理解

    作者回复: 我觉得可以

    
     1
  • 随风而逝
    2019-04-30
    老师,这些原子操作类在分布式程序中还有效吗?

    作者回复: 无效

    
     1
  • linqw
    2019-04-21
    课后习题:如果在do{}while()第一次没设置成功,即对象已经被其他线程修改,or已经是过期的对象,导致死循环,可以写成如:
    public class SafeWM {
      class WMRange{
        final int upper;
        final int lower;
        WMRange(int upper,int lower){
        if(upper < lower){
                    throw new IllegalArgumentException();
              }
        // 省略构造函数实现
        }
      }
      final AtomicReference<WMRange>
        rf = new AtomicReference<>(
          new WMRange(0,0)
        );
      // 设置库存上限
      void setUpper(int v){
        WMRange nr;
        WMRange or;
        do{
          or = = rf.get();
          nr = new
            WMRange(v, or.lower);
        }while(!rf.compareAndSet(or, nr));
      }
    }
    展开

    作者回复: 👍

    
     1
  • Mark
    2019-04-18
    请教一个问题
    compareAndSwapLong 更新完后返回的是true false,再return v。这是两步操作,return v之前,内存值有可能已经被该了,不是v了。
    有这种可能吗?

    作者回复: 有这种可能

    
     1
  • 小萝卜
    2019-04-16
    第16行应该放在循环体内
    
     1
  • 乾坤瞬间
    2020-01-11
    CAS理解的关键所在A为内存中上次的值,由于可见性问题,线程处理A的时候,会加载到当前线程中的工作空间中,因此。下次更新的的时候,只要保证当前的A与工作空间中的值一直的时候才能拥有被更新的操作,同时读内存的值与写内存值的操作必须要互斥,否则,在更新值的同时有一个线程T读取了内存相关的内存值,此时,T线程仍然会更新,这个是如何实现的?
    
    
我们在线,来聊聊吧