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,到此結束

相關文章
相關標籤/搜索