原子操作是指一個不受其他操作影響的操作任務單元。原子操作是在多線程環境下避免數據不一致必須的手段。
int++並不是一個原子操作,所以當一個線程讀取它的值並加1時,另外一個線程有可能會讀到之前的值,這就會引發錯誤。
爲了解決這個問題,必須保證增加操作是原子的,可以通過volatile、synchronized關鍵字來解決併發訪問的安全問題,但是這樣解決太麻煩。
java.util.concurrent.atomic包提供了int和long類型的裝類,它們可以自動的保證對於他們的操作是原子的並且不需要使用同步。
下面給出一個反面例子:
public class Main {
public static void main(String args[]){
//創建一個線程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//創建五個線程
Runnable runnable1=new RunnableImpl("張三",2000);
Runnable runnable2=new RunnableImpl("李四",1000);
Runnable runnable3=new RunnableImpl("王五",3000);
Runnable runnable4=new RunnableImpl("趙六",4000);
Runnable runnable5=new RunnableImpl("陳七",2000);
Runnable runnable6=new RunnableImpl("王八",2000);
Runnable runnable7=new RunnableImpl("毛九",5000);
//執行各個線程
executorService.execute(runnable1);
executorService.execute(runnable2);
executorService.execute(runnable3);
executorService.execute(runnable4);
executorService.execute(runnable5);
executorService.execute(runnable6);
executorService.execute(runnable7);
//關閉線程池
executorService.shutdown();
}
}
class RunnableImpl implements Runnable {
private static AtomicLong atomicLong=new AtomicLong(10000);
private String name; //操作人
private int x; //操作金額
RunnableImpl(String name,int x){
this.name=name;
this.x=x;
}
@Override
public void run() {
System.out.println(name+"執行了"+x+",當前餘額:"+atomicLong.addAndGet(x));
}
}
運行結果如下:
張三執行了2000,當前餘額:12000
王五執行了3000,當前餘額:16000
趙六執行了4000,當前餘額:20000
陳七執行了2000,當前餘額:22000
王八執行了2000,當前餘額:24000
毛九執行了5000,當前餘額:29000
李四執行了1000,當前餘額:13000
張三執行了2000,當前餘額:12000
李四執行了1000,當前餘額:13000
王五執行了3000,當前餘額:16000
趙六執行了4000,當前餘額:20000
陳七執行了2000,當前餘額:22000
王八執行了2000,當前餘額:24000
毛九執行了5000,當前餘額:29000
從結果可以看出,這樣的計算結果還是存在問題,原子量雖然保證了單個變量在某一個操作上的安全,但是它無法保證整個程序的安全性,下面對錯誤進行修正:
public class Main {
public static void main(String args[]){
//創建一個線程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//創建一個鎖對象
Lock lock=new ReentrantLock(false);
//創建五個線程
Runnable runnable1=new RunnableImpl("張三",2000,lock);
Runnable runnable2=new RunnableImpl("李四",1000,lock);
Runnable runnable3=new RunnableImpl("王五",3000,lock);
Runnable runnable4=new RunnableImpl("趙六",4000,lock);
Runnable runnable5=new RunnableImpl("陳七",2000,lock);
Runnable runnable6=new RunnableImpl("王八",2000,lock);
Runnable runnable7=new RunnableImpl("毛九",5000,lock);
//執行各個線程
executorService.execute(runnable1);
executorService.execute(runnable2);
executorService.execute(runnable3);
executorService.execute(runnable4);
executorService.execute(runnable5);
executorService.execute(runnable6);
executorService.execute(runnable7);
//關閉線程池
executorService.shutdown();
}
}
class RunnableImpl implements Runnable {
private static AtomicLong atomicLong=new AtomicLong(10000);
private String name; //操作人
private int x; //操作金額
private Lock lock;
RunnableImpl(String name,int x,Lock lock){
this.name=name;
this.x=x;
this.lock=lock;
}
@Override
public void run() {
lock.lock();
System.out.println(name+"執行了"+x+",當前餘額:"+atomicLong.addAndGet(x));
lock.unlock();
}
}
運行結果如下:
張三執行了2000,當前餘額:12000
王五執行了3000,當前餘額:15000
趙六執行了4000,當前餘額:19000
陳七執行了2000,當前餘額:21000
王八執行了2000,當前餘額:23000
毛九執行了5000,當前餘額:28000
李四執行了1000,當前餘額:29000