java 原子类,基本类型原子类

发布于:2021-07-26 23:28:41

[TOC]


# 简介


使用原子的方式更新基本类型


* AtomicInteger:int类型原子类


* AtomicLong:long类型原子类


* AtomicBoolean :boolean类型原子类


上面三个类提供的方法几乎相同,这里以 AtomicInteger 为例子来介绍


# AtomicInteger 类常用方法


~~~


public final int get()//获取当前的值


public final int getAndSet(int?newValue)//获取当前的值,并设置新的值


public final intgetAndIncrement()//获取当前的值,并自增


public final intgetAndDecrement()//获取当前的值,并自减


public final intgetAndAdd(int?delta)//获取当前的值,并加上预期的值


boolean compareAndSet(int?expect,?int?update)//如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)


public final voidlazySet(int?newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值


~~~


# 部分源码


~~~


private static final Unsafe unsafe = Unsafe.getUnsafe();


private static final long valueOffset;


static {


try {


valueOffset = unsafe.objectFieldOffset


(AtomicInteger.class.getDeclaredField("value"));


} catch (Exception ex) { throw new Error(ex); }


}


private volatile int value;


~~~


> 2个关键字段说明:


> **value**:使用volatile修饰,可以确保value在多线程中的可见性。


> **valueOffset**:value属性在AtomicInteger中的偏移量,通过这个偏移量可以快速定位到value字段,这个是实现AtomicInteger的关键。


**getAndIncrement源码:**


~~~


public?final?int?getAndIncrement()?{


return?unsafe.getAndAddInt(this,?valueOffset,?1);


}


~~~


内部调用的是**Unsafe**类中的**getAndAddInt**方法,我们看一下**getAndAddInt**源码:


~~~


// var1是this, var4是1, var2是旧的预期值


public final int getAndAddInt(Object var1, long var2, int var4) {


int var5;


do {


//var5是新的真实值


var5 = this.getIntVolatile(var1, var2);


} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));


return var5;


}


~~~


~~~


说明:


this.getIntVolatile:可以确保从主内存中获取变量最新的值。


compareAndSwapInt:CAS操作,CAS的原理是拿期望的值和原本的值作比较,如果相同则更新成新的值,可以确保在多线程情况下只有一个线程会操作成功,不成功的返回false。


上面有个do-while循环,compareAndSwapInt返回false之后,会再次从主内存中获取变量的值,继续做CAS操作,直到成功为止。


getAndAddInt操作相当于线程安全的count++操作,如同:


synchronize(lock){


count++;


}


count++操作实际上是被拆分为3步骤执行:


1. 获取count的值,记做A:A=count


2. 将A的值+1,得到B:B = A+1


3. 让B赋值给count:count = B


多线程情况下会出现线程安全的问题,导致数据不准确。


synchronize的方式会导致占时无法获取锁的线程处于阻塞状态,性能比较低。CAS的性能比synchronize要快很多。


~~~


# 例子


~~~


@Slf4j


public class AtomicExample1 {


// 请求总数


public static int clientTotal = 5000;


// 同时并发执行的线程数


public static int threadTotal = 200;


public static AtomicInteger count = new AtomicInteger(0);


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();


add();


semaphore.release();


} catch (Exception e) {


log.error("exception", e);


}


countDownLatch.countDown();


});


}


countDownLatch.await();


executorService.shutdown();


log.info("count:{}", count.get());


}


private static void add() {


count.incrementAndGet();


// count.getAndIncrement();


}


}


~~~

相关推荐

最新更新

猜你喜欢