Java原子類Atomic原理和應用
阿新 • • 發佈:2019-01-27
jdk所提供的原子類可以大致分為四種類型:
- 原子更新基本資料型別
- 原子更新陣列型別
- 原子更新抽象資料型別
- 原子更新欄位
先來看看jdk提供的原子類(rt.jar包下java.util.concurrent.atomic):
首先我們來寫一個數字自增生成器
package cn.itcats.thread.safe.Test1; public class Sequence { private int a = 0; public int add() { return a++; } public static void main(String[] args) { Sequence sequence = new Sequence(); new Thread(new Runnable() { public void run() { while (true) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + sequence.add()); } } }).start(); new Thread() { public void run() { while (true) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + sequence.add()); } }; }.start(); } }
列出部分的執行結果:
Thread-0 0
Thread-1 0
Thread-1 1
Thread-0 1
Thread-1 2
Thread-0 3
Thread-1 4
Thread-0 5
明顯可見存線上程安全問題,這也就是我們正需要解決的問題
add()方法中 a++; 並不是一個原子性操作,我們使用原子類把int a變成一個原子類
package cn.itcats.thread.safe.Test1; import java.util.concurrent.atomic.AtomicInteger; public class Sequence { //使用原子類AtomicInteger private AtomicInteger a = new AtomicInteger(0); public int add() { return a.getAndIncrement(); //先獲取再自增,對應a++ //若使用++a 則對應方法是a.incrementAndGet(); 先自增再獲取 , //多說一句 a-- 就是 a.getAndDecrement(); //若a = a + 10;————對應API a.getAndAdd(10); } public static void main(String[] args) { Sequence sequence = new Sequence(); new Thread(new Runnable() { public void run() { while (true) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + sequence.add()); } } }).start(); new Thread() { public void run() { while (true) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " " + sequence.add()); } }; }.start(); } }
再看執行結果發現,並沒有出現重複的數字。因此我們對數值的一些非原子性操作,都可以使用原子類轉化為原子性操作。
除了對int等基本資料型別的操作,還可以對陣列使用原子類進行原子性操作。
private int[] s = {1,2,3};
AtomicIntegerArray array = new AtomicIntegerArray(s);
public int arrayAdd() {
return array.getAndAdd(0, 10);
}
對原子更新抽象資料型別進行設定和獲取 AtomicReference<User> at = new AtomicReference<User>();
原子更新欄位 如更新User欄位屬性
AtomicIntegerFieldUpdater<User> userAto = AtomicIntegerFieldUpdater.newUpdater(User.class,"name");
相關API不一一說明了,因為用的不算太多。