假設如今有這樣的一個場景: 一百個線程同時對一個int對象進行修改,要求只能有一個線程能夠修改。ide
看看下面程序是否正確:工具
private static int a = 100; private static volatile boolean ischanged = false; public static void main(String[] args){ for(int i=0; i<100;i++){ Thread t = new Thread(new Runnable() { @Override public void run() { if(!ischanged){ ischanged = true; a = 120; } } }); t.start(); } }
對於volatile變量,寫的時候會將線程本地內存的數據刷新到主內存上,讀的時候會將主內存的數據加載到本地內存裏,因此能夠保證可見行和單個讀/寫操做的原子性。可是上例中先 1. 判斷!ischanged 2.ischanged=true 該組合操做就不能保證原子性了,也就是說線程A A1->A2 線程B B1->B2(第一個操做爲volatile讀或者第二個操做爲volatile寫的時候,編譯器不會對兩個語句重排序,因此最後的執行順序知足順序一致性模型的),可是最後的執行結果多是A1->B1->A2->B2。不知足需求spa
AtomicIntegerFieldUpdater: 基於反射的工具,可用CompareAndSet對volatile int進行原子更新:線程
修改上個場景的代碼,以下:code
public class Test{
private static AtomicIntegerFieldUpdater<Test> update = AtomicIntegerFieldUpdater.newUpdater(Test.class, "a"); private static Test test = new Test(); public volatile int a = 100; public static void main(String[] args){ for(int i=0; i<100;i++){ Thread t = new Thread(new Runnable() { @Override public void run() { if(update.compareAndSet(test, 100, 120)){ System.out.print("已修改"); } } }); t.start(); } }
}
用AtomicIntegerFieldUpdater.newUpdater指定類裏面的屬性。這裏咱們要更新Test類裏面的A字段(必須是volatile且不是static對象)。update.compareAndSet()方法使用cas機制,每次提交的時候都比較下test.a是否是100,若是是,則更新。