Analysis and use of atomic classes

Atomic class

1. The role and introduction of atoms.

1.1 Features

  • inseparable
  • An operation is uninterruptible , even in multi-threaded situations.

1.2 Function

  • Used when certain variables need to be thread-safe.

  • The function of atomic classes is similar to that of locks, which is to ensure thread safety in concurrent situations. However, atomic classes have certain advantages over locks :

    • Finer granularity : Atomic variables can reduce the scope of competition to the variable level. At this time, we can obtain the finest granularity. Usually the granularity of locks is greater than that of atomic variables.
    • More efficient : Generally, using atomic classes is more efficient than using locks, except in highly competitive situations.

2. 6 types of atoms

[The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-KYPXC70s-1600216554785)(%E5%8E%9F%E5%AD%90%E7%B1%BB .assets/image-20200915172735035.png)]

2.1. Atomic* basic type atomic class

2.1.1AtomicInteger

Common methods

  1. public final int get();
  2. public final int getAndSet(int newValue)//Get the current value and set the new value
  3. public final int getAndIncrement();//Get the current value and increment it.
  4. public final int getAndAdd(int data);//Get the current value and add data.
  5. boolean compareAndSet(int expect, int newValue);//If it is the expected value, replace it with newValue.

Code demo :

/**
 * 描述:     演示AtomicInteger的基本用法,对比非原子类的线程安全问题,使用了原子类之后,不需要加锁,也可以保证线程安全。
 */
public class AtomicIntegerDemo1 implements Runnable {

    private static final AtomicInteger atomicInteger = new AtomicInteger();

    public void incrementAtomic() {
        atomicInteger.getAndAdd(1);
    }

    private static volatile int basicCount = 0;

    public  void incrementBasic() {
        basicCount++;
    }

    public static void main(String[] args) throws InterruptedException {
        AtomicIntegerDemo1 r = new AtomicIntegerDemo1();
        Thread t1 = new Thread(r);
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("原子类的结果:" + atomicInteger.get());
        System.out.println("普通变量的结果:" + basicCount);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            incrementAtomic();
            incrementBasic();
        }
    }
}

Result of atomic class: 20000
Result of ordinary variable: 19672

  • AtomicLong
  • AtomicBoolean

2.1.2Atomic array

code demo


/**
 * 描述:     演示原子数组的使用方法
 */
public class AtomicArrayDemo {

    public static void main(String[] args) {
        //创建长度为1000的数据,初始化为0-
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000);
        Incrementer incrementer = new Incrementer(atomicIntegerArray);
        Decrementer decrementer = new Decrementer(atomicIntegerArray);
        //建立两个包含100个线程的线程数组
        Thread[] threadsIncrementer = new Thread[100];
        Thread[] threadsDecrementer = new Thread[100];
        for (int i = 0; i < 100; i++) {
            threadsDecrementer[i] = new Thread(decrementer);
            threadsIncrementer[i] = new Thread(incrementer);
            threadsDecrementer[i].start();
            threadsIncrementer[i].start();
        }

//        Thread.sleep(10000);
        for (int i = 0; i < 100; i++) {
            try {
                threadsDecrementer[i].join();
                threadsIncrementer[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //自加了一千次,自减了一千次。所以最后结果为0
        for (int i = 0; i < atomicIntegerArray.length(); i++) {
//            if (atomicIntegerArray.get(i)!=0) {
//                System.out.println("发现了错误"+i);
//            }
            System.out.println(atomicIntegerArray.get(i));
        }
        System.out.println("运行结束");
    }
}

class Decrementer implements Runnable {

    private AtomicIntegerArray array;

    public Decrementer(AtomicIntegerArray array) {
        this.array = array;
    }

    @Override
    public void run() {
        for (int i = 0; i < array.length(); i++) {
            //每个位置自减
            array.getAndDecrement(i);
        }
    }
}

class Incrementer implements Runnable {

    private AtomicIntegerArray array;

    public Incrementer(AtomicIntegerArray array) {
        this.array = array;
    }

    @Override
    public void run() {
        for (int i = 0; i < array.length(); i++) {
            array.getAndIncrement(i);
        }
    }
}

2.1.3 Upgrade ordinary variables to have atomic functions.

  • AtomicIntegerFieldUpdater upgrades ordinary variables .

  • Usage scenario: Occasionally an atomic get-set operation is required.

  • Code demo:

    
    /**
     * 描述:     演示AtomicIntegerFieldUpdater的用法
     */
    public class AtomicIntegerFieldUpdaterDemo implements Runnable{
    
        static Candidate tom;
        static Candidate peter;
    
        public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater
                .newUpdater(Candidate.class, "score");
    
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                peter.score++;
                scoreUpdater.getAndIncrement(tom);
            }
        }
    
        public static class Candidate {
            volatile int score;
        }
    
        public static void main(String[] args) throws InterruptedException {
            tom=new Candidate();
            peter=new Candidate();
            AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
            Thread t1 = new Thread(r);
            Thread t2 = new Thread(r);
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println("普通变量:"+peter.score);
            System.out.println("升级后的结果"+ tom.score);
        }
    }
    
    

    Ordinary variables: 18696
    upgraded result 20000

3. Adder accumulator

  • It was introduced in Java8 and is a relatively new class.

  • LongAdder is more efficient than AtomicLong under high concurrency . It is essentially space for time.

  • When competition is fierce, LongAdder maps different threads to different Cells for modification, reducing the probability of conflicts. This is the concept of multi-segment locking , which improves concurrency.

  • Code demonstration of AtomicLong and LongAdder.

    /**
     * 描述:     演示高并发场景下,LongAdder比AtomicLong性能好
     */
    public class AtomicLongDemo {
    
        public static void main(String[] args) throws InterruptedException {
            AtomicLong counter = new AtomicLong(0);
            ExecutorService service = Executors.newFixedThreadPool(20);
            long start = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {
                service.submit(new Task(counter));
            }
            service.shutdown();
            while (!service.isTerminated()) {
    
            }
            long end = System.currentTimeMillis();
            System.out.println(counter.get());
            System.out.println("AtomicLong耗时:" + (end - start));
        }
    
        private static class Task implements Runnable {
    
            private AtomicLong counter;
    
            public Task(AtomicLong counter) {
                this.counter = counter;
            }
    
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    counter.incrementAndGet();
                }
            }
        }
    }
    
    /**
     * 描述:    TODO 演示高并发场景下,LongAdder比AtomicLong性能好
     */
    public class LongAdderDemo {
    
        public static void main(String[] args) throws InterruptedException {
            LongAdder counter = new LongAdder();
            ExecutorService service = Executors.newFixedThreadPool(20);
            long start = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {
                service.submit(new Task(counter));
            }
            service.shutdown();
            while (!service.isTerminated()) {
    
            }
            long end = System.currentTimeMillis();
            System.out.println(counter.sum());
            System.out.println("LongAdder耗时:" + (end - start));
        }
    
        private static class Task implements Runnable {
    
            private LongAdder counter;
    
            public Task(LongAdder counter) {
                this.counter = counter;
            }
    
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    counter.increment();
                }
            }
        }
    }
    
    

    Cause Analysis

    • ​ Due to the fierce competition, flush and refresh must be performed for each addition, which consumes a lot of resources. Every addition needs to be synchronized.

    • As for LongAdder, each thread has its own counter, which is only used for counting within its own thread, so that it will not be interfered by the counters of other threads. Finally, the counters of all threads are summarized to obtain the cumulative number.

    • LongAdder introduces the concept of segmented accumulation. There is a base variable and a Cell[] array inside to participate in the counting:

      • Base variable: The competition is not fierce and is directly accumulated to this variable.

      • Cell[] array: The competition is fierce, and each thread is scattered and accumulated into its own Cell[i].

      • sum source code analysis. It can be seen from the source code that no lock is added during the accumulation process, as[i] may still change during the addition process, and it is still thread-unsafe .

        [The external link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-92IU5DK5-1600216554787) (%E5%8E%9F%E5%AD%90%E7%B1%BB. assets/image-20200916082202165.png)]

Guess you like

Origin blog.csdn.net/qq_45372719/article/details/108614215