引出
由於原子性的類型是後期引出的,但是想讓原來已經寫好的屬性也具有原子性,就可以利用這個類
AtomicXXXFieldUpdater主要包括以下幾個:AtomicIntegerFieldUpdater
,AtomicLongFieldUpdater
,AtomicReferenceFieldUpdater
。
要求
- 字段必須是volatile類型的,在線程之間共享變量時保證立即可見
- 字段的描述類型(修飾符public/protected/default/private)是與調用者與操作對象字段的關係一致。也就是說調用者能夠直接操作對象字段,那麼就可以反射進行原子操作。
- 對於父類的字段,子類是不能直接操作的,儘管子類可以訪問父類的字段。
- 只能是實例變量,不能是類變量,也就是說不能加static關鍵字。
- 只能是可修改變量,不能使final變量,因爲final的語義就是不可修改。
- 對於AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long類型的字段,不能修改其包裝類型(Integer/Long)。如果要修改包裝類型就需要使用AtomicReferenceFieldUpdater
舉例使用
public class AtomicXXXFieldUpdater {
public static void main(String[] args) throws InterruptedException {
TestMe testMe = new TestMe();
Set<Integer> data = new HashSet<>();
for (int i = 0; i < 3; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 500; j++) {
testMe.updateNum();
}
});
thread.start();
thread.join();
}
System.out.println(data.size());
}
}
class TestMe {
private volatile int num = 0;
public void updateNum(){
AtomicIntegerFieldUpdater updaterNum = AtomicIntegerFieldUpdater.newUpdater(getClass(),"num");
int i = updaterNum.incrementAndGet(this);
System.out.println(i);
}
}
使用場景總結
1. 想讓其他的類的屬性具備原子性
2. 不想使用任何鎖
3.大量需要原子類型修飾的對象,相比較會消耗內存
- 如果直接使用原子類型修飾,需要包裝所有的數據
- 但是通過Updater更新,只需要每次更新其中一個數據