What do we know about these contents under the Atomic package?

Hello everyone, I’m 方圆
here. Let’s mainly write about the things that are elevated under the Atomic package


1. Recognize and recognize atomic classes

The role of the atomic class is similar to the lock, it is to ensure concurrency 线程安全, and its 粒度更细,效率更高


2. Overview of Atomic Classes

Insert picture description here


3. AtomicIntegerFieldUpdater

This class can be used when we need to perform atomic operations on a field 升级, so that it saves space and optimizes performance.

3.1 Code demonstration

Note that it should be modified with volatile, but cannot be modified with 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());
    }
}
  • Test Results
    Insert picture description here
    Insert picture description here

4. Adder accumulator

  • It was added in JDK1.8
  • Compared with AtomicLong under high concurrency, LongAdder is 效率更高essentially used 空间换时间(we will take a look at the source code later)
  • LongAdder puts different threads corresponding to different Cells, and it maintains one at the bottom Cell数组, which is equivalent to the concept of multi-segment locks, which improves the performance of concurrency

4.1 LongAdder code test

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");
    }
}
  • result:
    Insert picture description here

4.2 AtomicLong code test

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

    }
}
  • result
    Insert picture description here

4.3 Summary

We can find that under high concurrency, LongAdder has better performance, mainly when AtomicLong is in 每一次加法place flush和refresh(in JMM, synchronize back and forth between its own working memory and main memory), resulting in a waste of resources

The implementation of LongAdder is originally different from AtomicLong. It does not need to be synchronized, but each thread has its own counter, and no thread will unify the count.
There are two important variables, Cell数组and the base基值former is high. Used in concurrency, each thread records its own accumulated value. The latter is used when the competition is not fierce, and it is directly added to the base variable.
Insert picture description here
We read sum方法the source code
Insert picture description here

In the case of low concurrency, AtomicLong and LongAdder have almost the same performance, but when the concurrency increases, the throughput of LongAdder is large, but it consumes more space, essentially using space for time; on the other hand, LongAdder No CAS method is provided. This is its shortcoming compared to AtomicLong. LongAdder is more suitable for statistical summation and counting scenarios.


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

Insert picture description here
It is equivalent to an upgrade to LongAdder, we can specify the calculation formula, its bottom layer also maintains the Cell array and base base value, and can perform multi-threaded calculations


Come on! ! !

Guess you like

Origin blog.csdn.net/qq_46225886/article/details/108042737