- AtomicBoolean:原子更新布爾類型
- AtomicInteger:原子更新整型
- AtomicLong:原子更新長整型
- int addAndGet(int delta):以原子方式將輸入的數值與實例中的值(AtomicInteger裏的 value)相加,並返回結果。
- boolean compareAndSet(int expect,int update):如果輸入的數值等於預期值,則以原子方式將該值設置爲輸入的值。
- int getAndIncrement():以原子方式將當前值加1,注意,這裏返回的是自增前的值,等價於i++。
- int incrementAndGet():以原子方式將當前值加1,等價於++1。
3.AtomicBoolean案例演示 參考:AtomicBoolean介紹與使用
@Slf4j
@ThreadSafe
public class AtomicBooleanTest {
private static AtomicBoolean isHappened = new AtomicBoolean(false);
// 請求總數
public static int clientTotal = 5000;
// 同時併發執行的線程數
public static int threadTotal = 200;
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
test();
semaphore.release();
} catch (Exception e) {
log.error("exception", e);
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("isHappened:{}", isHappened.get());
}
private static void test() {
//併發同步控制,保證只有一個線程執行
if (isHappened.compareAndSet(false, true)) {
log.info("execute");
}
}
}
4.AtomicInteger案例演示
//結果:i = 10 j = 20
AtomicInteger atomicInteger = new AtomicInteger();
int i = atomicInteger.addAndGet(10);
int j = atomicInteger.addAndGet(10);
System.out.println("i = " + i);
System.out.println("j = " + j);
//等價於i++ reuslt1 = 0
AtomicInteger atomicInteger1 = new AtomicInteger();
int reuslt1 = atomicInteger1.getAndIncrement();
System.out.println("reuslt1 = " + reuslt1);
//等價於++i reuslt2 = 1
AtomicInteger atomicInteger2 = new AtomicInteger();
int reuslt2 = atomicInteger2.incrementAndGet();
System.out.println("reuslt2 = " + reuslt2);
//result3 = 100
AtomicInteger atomicInteger3 = new AtomicInteger(10);
atomicInteger3.getAndSet(100);
int result3 = atomicInteger3.get();
System.out.println("result3 = " + result3);
//CAS樂觀鎖和數據庫樂觀鎖類似 b1 = false b2 = true
AtomicInteger atomicInteger4 = new AtomicInteger(10);
boolean b1 = atomicInteger4.compareAndSet(11, 100);
boolean b2 = atomicInteger4.compareAndSet(10, 100);
System.out.println("b1 = " + b1);
System.out.println("b2 = " + b2);
5.使用原子類確保線程安全
@NotThreadSafe
public class UnsafeSequences {
//多個線程併發訪問共享變量n,線程不安全
private int n;
private int add(){
return n++;
}
public static void main(String[] args) {
Thread t ;
UnsafeSequences unsafeSequences =new UnsafeSequences();
for (int i = 0; i <10000 ; i++) {
t= new Thread(new Runnable() {
@Override
public void run() {
int reuslt = unsafeSequences.add();
System.out.println("reuslt = " + reuslt);
}
});
t.start();
}
}
}
@ThreadSafe
public class SafeSequence {
private static AtomicInteger atomicInteger =new AtomicInteger();
private int add(){
return atomicInteger.getAndIncrement();
}
public static void main(String[] args) throws InterruptedException {
Thread t ;
for (int i = 0; i <10000 ; i++) {
t= new Thread(new Runnable() {
@Override
public void run() {
new SafeSequence().add();
}
});
t.start();
t.join();
}
System.out.println(atomicInteger.get());
}
}
6.getAndIncrement方法實現原子操作原理分析
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
var1:指的是AtomicInteger對象
var2:指的是valueOffset內存首地址偏移量--當前值
var4:指的是常量1
var5:內存中的值--期望值
當var2當前值和var5期望值相等的情況下,將值更新爲var5+var4
(三)原子更新數組
1.通過原子的方式更新數組裏的某個元素,Atomic包提供了以下4個類。
- AtomicIntegerArray:原子更新整型數組裏的元素
- AtomicLongArray:原子更新長整型數組裏的元素
- AtomicReferenceArray:原子更新引用類型數組裏的元素
- ·int addAndGet(int i,int delta):以原子方式將輸入值與數組中索引i的元素相加
- boolean compareAndSet(int i,int expect,int update):如果當前值等於預期值,則以原子
方式將數組位置i的元素設置成update值。
2.案例演示
@ThreadSafe
public class AtomicIntegerArrayDemo {
public static void main(String[] args) {
int[] a = {5,6,7,8,9};
AtomicIntegerArray array = new AtomicIntegerArray(a);
array.addAndGet(0,1);
int result = array.get(0);
//result = 6
System.out.println("result = " + result);
//array = [6, 6, 7, 8, 9]
System.out.println("array = "+array.toString());
//array = [5, 6, 7, 8, 9]
array.compareAndSet(0,6,5);
System.out.println("array = "+array.toString());
}
}
(四) 原子更新引用類型
- AtomicReference:原子更新引用類型
- AtomicReferenceFieldUpdater:原子更新引用類型裏的字段
- AtomicMarkableReference:原子更新帶有標記位的引用類型。可以原子更新一個布爾類 型的標記位和引用類型。構造方法是AtomicMarkableReference(V initialRef,boolean initialMark)
1.AtomicReference案例演示
public class AtomicReferenceTest {
private static AtomicReference atomicReference = new AtomicReference();
public static void main(String[] args) {
Person person1 = new Person();
person1.setName("zhangsan");
person1.setAge(18);
atomicReference.set(person1);
Person person2 = new Person();
person2.setName("lisi");
person2.setAge(22);
atomicReference.compareAndSet(person1,person2);
//結果:Person{name='lisi', age=22}
System.out.println(atomicReference);
}
static class Person{
private String name;
private int age;
}
}
2.AtomicReferenceFieldUpdater案例演示
public class AtomicReferenceFieldUpdaterTest {
private static AtomicReferenceFieldUpdater updater=AtomicReferenceFieldUpdater.newUpdater(Person.class,String.class,"name");
public static void main(String[] args) {
Person person = new Person();
person.setName("zhangsan");
person.setAge(18);
updater.compareAndSet(person, person.getName(),"lisi");
//結果:name = lisi
System.out.println("name = "+person.getName());
//將lisi修改爲wangwu
updater.getAndSet(person,"wangwu");
System.out.println("name = "+person.getName());
}
static class Person{
volatile String name;
volatile int age;
}
}
(五)原子更新類字段
- AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
- AtomicLongFieldUpdater:原子更新長整型字段的更新器
- AtomicStampedReference:原子更新帶有版本號的引用類型。該類將整數值與引用關聯起
來,可用於原子的更新數據和數據的版本號,可以解決使用CAS進行原子更新時可能出現的ABA問題。
@Slf4j
public class AtomicIntegerFieldUpdaterTest {
//第一步,因爲原子更新字段類都是抽象類,每次使用的時候必須使用靜態方法newUpdater()創建一個更新器,並且需要設置想要更新的類和屬性。
private static AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdaterTest> updater =
AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdaterTest.class, "count");
//第二步,更新類的字段(屬性)必須使用public volatile修飾符。
@Getter
public volatile int count = 100;
public static void main(String[] args) {
AtomicIntegerFieldUpdaterTest updaterTest = new AtomicIntegerFieldUpdaterTest();
if (updater.compareAndSet(updaterTest, 100, 120)) {
//update success 1, 120
log.info("update success 1, {}", updaterTest.getCount());
}
if (updater.compareAndSet(updaterTest, 100, 120)) {
log.info("update success 2, {}", updaterTest.getCount());
} else {
// update failed 3, 120
log.info("update failed 3, {}", updaterTest.getCount());
}
}
}
(六)Atomic包下相關面試題目