大家好,我是
方圆
我们来主要写写Atomic包下拔高的东西
目录
1. 重新认识认识原子类
原子类的作用与锁类似,是为了保证并发情况下的线程安全
,而且它的粒度更细
,效率更高
2. 原子类纵览
3. AtomicIntegerFieldUpdater
在我们需要对一个字段进行原子操作的时候可以用这个类来进行升级
,这样它节省了空间也优化了性能。
3.1 代码演示
注意要用volatile修饰,但是不能用static修饰
public class AtomicIntegerFieldUpdateDemo implements Runnable{
//TODO 注意字段需要被volatile修饰,但是不能是static修饰的
private volatile int a = 0;
private volatile int b = 0;
//用法有点儿像反射
private static final AtomicIntegerFieldUpdater<AtomicIntegerFieldUpdateDemo> updater =
AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFieldUpdateDemo.class,"a");
public int getA() {
return a;
}
public int getB() {
return b;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
updater.getAndIncrement(this);
b++;
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
AtomicIntegerFieldUpdateDemo demo = new AtomicIntegerFieldUpdateDemo();
new Thread(demo).start();
new Thread(demo).start();
TimeUnit.SECONDS.sleep(1);
System.out.println("升级过的int " + demo.getA());
System.out.println("普通的int " + demo.getB());
}
}
- 测试结果
4. Adder累加器
- 它在JDK1.8被加入
- 在高并发下LongAdder相比于AtomicLong
效率更高
,本质上是用空间换时间
(后面我们会看一看源码) - LongAdder把不同的线程对应的不同的Cell上,它底层维护一个
Cell数组
,相当于是多段锁的概念,提高了并发的性能
4.1 LongAdder代码测试
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAdder;
public class LongAdderDemo implements Runnable{
private LongAdder longAdder;
public LongAdderDemo(LongAdder longAdder) {
this.longAdder = longAdder;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
longAdder.increment();
}
}
}
class TestLongAdder {
public static void main(String[] args) {
LongAdder adder = new LongAdder();
ExecutorService threadPool = Executors.newFixedThreadPool(8);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
threadPool.submit(new LongAdderDemo(adder));
}
threadPool.shutdown();
while(! threadPool.isTerminated()) {
}
long endTime = System.currentTimeMillis();
System.out.println(adder.sum());
System.out.println("耗时 " + (endTime - startTime) + "ms");
}
}
- 结果:
4.2 AtomicLong代码测试
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
public class AtomicLongDemo implements Runnable{
private AtomicLong atomicLong;
public AtomicLongDemo(AtomicLong atomicLong) {
this.atomicLong = atomicLong;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
atomicLong.incrementAndGet();
}
}
}
class TestAtomicDemo {
public static void main(String[] args) {
AtomicLong atomicLong = new AtomicLong();
ExecutorService threadPool = Executors.newFixedThreadPool(8);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
threadPool.submit(new AtomicLongDemo(atomicLong));
}
threadPool.shutdown();
while (! threadPool.isTerminated()) {
}
long endTime = System.currentTimeMillis();
System.out.println(atomicLong.get());
System.out.println("耗时 " + (endTime - startTime) + "ms");
}
}
- 结果
4.3 总结
我们可以发现,在高并发下,LongAdder有着更好的性能,主要是AtomicLong在每一次加法
的时候,都要进行flush和refresh
(JMM中,在自己的工作内存和主内存来回同步),导致很浪费资源
LongAdder的实现原来和AtomicLong是不同的,它并不需要进行同步,而是每个线程都有一个自己的计数器,没有一个线程会去进行计数统一
其中有两个重要的变量,Cell数组
和base基值
,前者在高并发的时候使用,每个线程记录自己的累加值,后者在竞争不激烈的时候使用,直接加在base变量上
我们读一读sum方法
的源码
在低并发的情况下,AtomicLong和LongAdder有着几乎一样的性能,不过当并发提高的时候,LongAdder的吞吐量很大,但是要耗费更多的空间,本质上就是用空间换时间;另一方面LongAdder没有提供CAS方法,这是它相比于AtomicLong的不足,LongAdder更适合的是统计求和和计数的场景
5. Accumulator累加器
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.stream.IntStream;
public class AccumulatorDemo {
public static void main(String[] args) {
LongAccumulator accumulator = new LongAccumulator((x,y) -> 2 * x + y,1);
ExecutorService threadPool = Executors.newFixedThreadPool(8);
IntStream.range(1,3).forEach(i -> threadPool.submit(() -> accumulator.accumulate(i)));
threadPool.shutdown();
while(! threadPool.isTerminated()) {
}
System.out.println(accumulator.getThenReset());
}
}
它相当于是对LongAdder的升级,我们能指定计算公式,它的底层同样也维护了Cell数组和base基值,能够进行多线程的计算
加油儿!!!