How incrementAndGet achieve thread-safe

Let's look at the definition of the security thread.
Definition: When multiple threads access a runtime environment regardless of class scheduling or the use of which will be how these processes are performed alternately
, and does not require any additional synchronization or collaboration, the main theme of this class in the code can show correct behavior, then call this class is thread-safe

Thread safety is mainly reflected in three aspects:

  • Atomic: provides exclusive access, only one thread at a time to operate it

  • Visibility: main memory repair a thread that can be observed in time to other threads

  • Ordering: a thread other threads observation instruction execution order, since there is an instruction reordering, the generally chaotic observation

Today, we look at the main atomicity is how to do it the same time, only one thread to operate it in the
Atomic package had filed Atomic introduction provided in jdk

In the previous study, we found that in the case do not do thread synchronization, a counter ++ will not get the results we want in a highly concurrent circumstances. So we look to combine source today is how to package Atomic we achieve thread-safe.

Let's look at a demo class

package com.imooc.concurrency.example.count;

import com.imooc.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author zty
 * @Date 2020/3/9 下午6:45
 * @Description:
 */
@Slf4j
@ThreadSafe
public class CountExample2 {
    //请求总数
    public static int cilentTotal = 5000;

    //同时并发执行的线程数
    public static int threadTotal = 200;
    //这里要注意,不要使用int 要使用Atomic提供的类
    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(cilentTotal);
        for (int i = 0; i < cilentTotal; i++){
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (InterruptedException e) {
                    log.error("exception",e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}",count.get());
    }

    private static void add(){
        count.incrementAndGet();
        //count.getAndIncrement();
    }
}

This is a thread-safe counters.
We first explain the difference between incrementAndGet and getAndIncrement the
way the two methods of treatment are the same, meaning the current value of +1 are based on the difference lies

getAndIncrement

The old value is returned (i.e. the original value prior to adding 1), and

incrementAndGet

Returns the new value (i.e., a value obtained by adding 1)

Today, we look at incrementAndGet main method is how to achieve thread-safe

Source code analysis

/**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

In this incrementAndGet, we can see the use of an unsafe class
unsafe in getAndAddInt provides a method, this method is not very important that its implementation

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

We specifically look at his realization, do a body through a do while statement to achieve the
core transfer method in a while statement is called inmpareAndSwapInt
We open to see its realization

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

This method is a native marked, this is representative of the underlying java code, the code is not us to achieve through java statement.

We continue to call back to see if this method getAndAddInt

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

First we passed over the first value is the current object, such as our case code of the count, the second value is our current value (For example, if we are to achieve the 2 + 1) Then var2 is 2 var4 is 1
var5 here, it is the way we call the bottom var5 = this.getIntVolatile (var1, var2) ; Get the current value of the underlying
if no other threads to handle this variable count time, it's normal the return value should be 2, thus compareAndSwapInt parameter is passed (count, 2,2,2 + 1), this method want to achieve this object it is to count the case if the current value and the bottom value equal next, that value is updated to put it back var5 + var4

When we come to a method, we var2 value is 2, the value of the first time we var5 taken out is also equal to 2, but when we perform the update to 3 when this code is

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

Other threads may be changed, so we have to determine whether the var5 var2 is the same, only the same before allowing it to update 3

By determining the same to stop the cycle, we can guarantee a desired value and the bottom

CAS比较与交换的伪代码可以表示为:

do{

备份旧数据;

基于旧数据构造新数据;

}while(!CAS( 内存地址,备份的旧数据,新数据 ))

CAS is the core compareAndSwapInt

Published 22 original articles · won praise 28 · views 2624

Guess you like

Origin blog.csdn.net/qq_43561507/article/details/104990202