這裡我主要讨論自增運算符(自減其實就是加-1,也是一種自增),那麼自增運算是一種原子性的運算嗎?先讨論操作對象是全局變量的情況
下面的代碼建立了100個線程:
mport java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo implements Runnable {
private int count=100;//建立線程數
private int num = 1;//要被自增的數
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<count;i++){
num++;
}
}
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ExecutorService service = Executors.newCachedThreadPool();
Demo demo = new Demo();
for(int i=0;i<100;i++){
service.execute(demo);
}
service.shutdown();
Thread.sleep(60000);
System.out.println(demo.num);
}
}
如果++是原子性的那麼最後列印結果應該是10000,如果不是則有可能 不是10000(為什麼說有可能呢?要是運氣,每個線程都在一個時間片内運作完,且沒有其他的因素使線程挂起,那麼線程就會順序執行,結果就會是10000,當然這種情況可以用Thread.sleep()方法使線程停一會兒來解決)
我的結果是8559小于10000,顯然++不是原子性的
我們也可以通過位元組碼來分析
code:
public class Demo01{
private int i=0;
public static void main(String[] args){
}
public void fun(){
i++;
}
}
用javap指令:javap verbose Demo01
會發現fun()的位元組碼是:
public void fun();
Code:
Stack=3, Locals=1, Args_size=1
0: aload_0
1: dup
2: getfield #2; //Field i:I
5: iconst_1
6: iadd
7: putfield #2; //Field i:I
10: return
LineNumberTable:
line 4: 0
line 5: 10
我門發現需要先獲得i(讀操作),然後将i壓入棧頂,然後iadd,顯然這是多步操作,當然是非原子性的
當然要是用synchronized上鎖,那就沒有問題了,但是會影響效率
第二種情況,局部變量自增
這種情況又分兩種情況,若局部變量在一個方法中,且這個方法啟動了多個線程,且多個線程同時通路這個變量,那也會出現問題(類似于全局的)
第二種情況是該方法沒有啟動多個線程,那麼局部變量隻在該方法内有效,是不是原子性的就沒有意義了