关于i++和++i的思考

概要:

i++ 返回原来的值,++i 返回加1后的值。

JAVA中:

java的编译器在遇到i++和i--的时候会重新为变量运算分配一块内存空间,以存放原始的值,而在完成了赋值运算之后,将这块内存释放掉。下面展示j=i++的过程:

java中二者都只能作为右值,不能作为左值。

C++中:

i++ 不能作为左值,而++i 可以。左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址。

int& int::operator++() //这里返回的是一个引用形式,就是说函数返回值也可以作为一个左值使用
{//函数本身无参,意味着是在自身空间内增加1的
  *this += 1;  // 增加
  return *this;  // 取回值
}

//后缀形式:
const int int::operator++(int) //函数返回值是一个非左值型的,与前缀形式的差别所在。
{//函数带参,说明有另外的空间开辟
  int oldValue = *this;  // 取回值
  ++(*this);  // 增加
  return oldValue;  // 返回被取回的值
}

JAVA中的拓展:

在多线程环境中,虽然在Java中++i是一条语句,字节码层面上也是对应iinc这条JVM指令,但是从最底层的CPU层面上来说,++i操作大致可以分解为以下3个指令:

  • 取数
  • 累加
  • 存储

其中的一条指令可以保证是原子操作,但是3条指令合在一起却不是,这就导致了++i语句不是原子操作。如果变量i用volatile修饰是否可以保证++i是原子操作呢,实际上这也是不行的。至于原因,参考volatile。如果要保证累加操作的原子性,可以采取下面的方法:

  1. 将++i置于同步块中,可以是synchronized或者J.U.C中的排他锁(如ReentrantLock等)。
  2. 使用原子性(Atomic)类替换++i,具体使用哪个类由变量类型决定。如果i是整形,则使用AtomicInteger类,其中的AtomicInteger#addAndGet()就对应着++i语句,不过它是原子性操作。
posted @ 2020-07-07 13:14  大嘤熊  阅读(234)  评论(0编辑  收藏  举报