Java中的"+"运算问题

首先明确,笔者在这不讨论"+"号做为字符串拼接的做用,而是做为运算符产生的问题。
也就是说下在Java中 i+1 、 i++ 、 ++i之间的区别java

含义

i+1

i++ 和 ++i 明显区别于 i+1 的是前二者的i的值都增长了。
若是给 i+1 赋值的话,又存在两种状况:安全

  • i = i+1;
    这个过程的结果至关于 ++i,i 在此次运算中增长了一个数。
  • j = i+1;
    在这个运算里 i 就至关于常量存在,自身不变。
int x=0;
    int y=0;
    while(x<10){
        x = x+1;
        System.out.print(x+" ");
    }
    System.out.println();
    while(y<10){
        ++y;
        System.out.print(y+" ");
    }
复制代码

运算结果:bash

1 2 3 4 5 6 7 8 9 10 
1 2 3 4 5 6 7 8 9 10 
复制代码

在循环中来讲,上面第一种状况的返回值的大小等价于 ++i ;第二种状况中 i 是不变的。多线程

i++ 与 ++i

这二者要放到一块儿讨论。
通俗来说,其中 i++ 是先赋值后运算; ++i 是先运算后赋值,但他们在Java中都只能做为右值使用,不能做为左值。并发

左值是对应(refer to)内存中有肯定存储地址的对象的表达式的值,而右值是全部不是左值的表达式的值。
这两个在循环中的代码:ui

int i = 0;
int j = 0;
while(i<6){
    int x = i++;
    System.out.print(x+""+i+" ");
}
System.out.println();
while(j<6){
    int y = ++j;
    System.out.print(y+""+j+" ");
}
复制代码

结果:atom

01 12 23 34 45 56 
11 22 33 44 55 66 
复制代码

他们在寄存器中的运算过程用代码表示以下:spa

i++ >>>
0: iconst_0               
1: istore_1               
2: iload_1                
3: iinc          1, 1     
6: istore_2  
7: return

++i >>>
0: iconst_0               
1: istore_1                
2: iinc          1, 1      
5: iload_1                 
6: istore_2      
7: return 
复制代码

也就是说i++ 运算中,栈顶值是 0 ,++i 运算中栈顶值是 1。线程

总的来讲,在 i++ 与 ++i 这两个运算中i都是增长了的,只是 i++ 返回的值是增长前的值, ++i 返回的值是增长后的值code

使用中的注意事项

1. 有一个骚操做 i = i++; while循环中出现这个基本就死循环了

int i = 0;
while (i < 2) {
    i = i++;
    System.out.println(i);
}
复制代码

结果就是一堆 0,你能够本身想一想是为何。
对了若是你的输出语句不换行控制台是打印不出消息的,由于结果长度超出限制了。

2.多线程中的并发问题

i++ 与 ++i 都并不是线程安全的运算,由于这二者都不是原子操做。

到这有人可能会想,是否能够用volatile关键字修饰来保证线程安全呢?答案是不能。由于volatile只能保证可见性,不能保证原子性。
那么到底怎么在多线程中保证这二者的线程安全呢?有两个办法:

  1. 用java.util.concurrent.atomic.AtomicInteger原子类下面的方法来替换这两个操做,固然这是整形的原子类,其余基本类型也有各自的原子类。这些原子类能保证原子操做。
  2. 同步块。加锁synchronized或者使用排他锁。

ok,到此结束

相关文章
相关标签/搜索