JUC包 — atomic包—AtomicInteger

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/java_yes/article/details/83864042

打开JUC包,看见的第一个就是atomic包,看下包结构:JAVA版本:1.8.0_172
atomic
我们简单的回顾一下原子性。

原子性

原子性是指:一个操作是不可中断的,要么全部执行成功,要么全部执行失败。在具体点,就是在多个线程一起执行的过程中,一个操作一旦开始,就不会被其他线程所干扰。以保证数据的准确性。
举几个常见的例子:


 1. int a = 10; 
 2. a++; 
 3. int b=a; 
 4. a = a+1; 

逐个分析:

  1. 将10 赋值给a;一步操作。
  2. 读取a的值;将a+1;将计算后的值赋值给a;三步操作。
  3. 读取a的值;将a的值赋值给b;两步操作。
  4. 同2;两步操作
    所以只有1具备原子性。

多线程不加锁自增:

用实例来看下2:

    static int count = 0;

    @Test
    public void thredInteger() throws InterruptedException {
        // 打印10次
        for (int j = 0; j < 10; j++) {
            count = 0;
            // 10个线程
            for (int i = 0; i < 10; i++) {
                new Thread() {
                    @Override
                    public void run() {
                        // 每个线程自增1000次
                        for(int k = 0; k < 1000; k++){
                            count++;
                        }
                    }
                }.start();
            }
            Thread.sleep(1000);
            System.out.println("count: " + count);
        }
    }

结果:可以看到有两条数据值出现问题。
testOne

那么我们要思考,如果保证数据的原子性呢,那既然是在多线程中出现的,我们用synchronized不就可以了。
好,我们试一下:

多线程使用synchronized自增:

    @Test
    public void synchronizedThredInteger() throws InterruptedException {
        Object object  = new Object();
        // 打印10次
        for (int j = 0; j < 10; j++) {
            count = 0;
            // 10个线程
            for (int i = 0; i < 10; i++) {
                new Thread() {
                    @Override
                    public void run() {
                        // 每个线程自增1000次
                        for (int k = 0; k < 1000; k++) {
                            synchronized (object){
                                count++;
                            }
                        }
                    }
                }.start();
            }
            Thread.sleep(1000);
            System.out.println("count: " + count);
        }
    }

结果:每次都是正确数据。
synchronizedCount
嘿,这TM不也可以么,为啥还要用Atomic包。
那么我们再来看下使用Atomic包下AtomicInteger类:

使用AtomicInteger

    static AtomicInteger atomicInteger = new AtomicInteger(0);

    @Test
    public void atomicInteger() throws InterruptedException {
        for (int j = 0; j < 10; j++) {
            atomicInteger = new AtomicInteger(0);
            for (int i = 0; i < 10; i++) {
                new Thread() {
                    @Override
                    public void run() {
                        // 每个线程自增1000次
                        for (int k = 0; k < 1000; k++) {
                            atomicInteger.getAndIncrement();
                        }
                    }
                }.start();
            }
            Thread.sleep(1000);
            System.out.println("atomicInteger: " + atomicInteger);
        }
    }

结果:每次都是正确数据。
在这里插入图片描述
所以我们通过实例证明了AtomicInteger是可以保证数据原子性的。

AtomicInteger源码:

/**
 * An {@code int} value that may be updated atomically.  See the
 * {@link java.util.concurrent.atomic} package specification for
 * description of the properties of atomic variables. An
 * {@code AtomicInteger} is used in applications such as atomically
 * incremented counters, and cannot be used as a replacement for an
 * {@link java.lang.Integer}. However, this class does extend
 * {@code Number} to allow uniform access by tools and utilities that
 * deal with numerically-based classes.
 *
 * @since 1.5
 * @author Doug Lea
*/
/**
 * 大意:
 * 1.可以以原子方式更新。
 * 2.用于原子递增计数器之类的应用操作,不能当做是Integer的替代品。
 * 3.但是这个类确实扩展了Number.class,允许处理基于数值的类的工具和实用工具的统一访问。
 */

主代码:

    // setup to use Unsafe.compareAndSwapInt for updates
   	// 使用Unsafe更新
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

常用方法:

    /**
     * Atomically increments by one the current value.
     * 递增当前一个当前值并保证原子性
     * @return the previous value
     * 返回原值
     */
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }      
    
   /**
     * Atomically increments by one the current value.
     * 递增当前一个当前值并保证原子性
     * @return the updated value
     * 返回更新后的值
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }
    
    /**
     * Atomically decrements by one the current value.
     *递减
     * @return the updated value
     */
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }
    
    /**
     * Atomically decrements by one the current value.
     * 递减
     * @return the previous value
     */
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

    /**
     * Atomically adds the given value to the current value.
     * 将给定值添加到当前值并保证原子性
     * @param delta the value to add
     * @return the previous value
     */
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    /**
     * Atomically adds the given value to the current value.
     * 将给定值添加到当前值并保证原子性
     * @param delta the value to add
     * @return the updated value
     */
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }
    
   /**
     * Atomically sets the value to the given updated value
     * if the current value {@code ==} the expected value.
     *
     * @param expect the expected value
     * @param update the new value
     * @return {@code true} if successful. False return indicates that
     * the actual value was not equal to the expected value.
     * 使用cas算法,更新数据
     */
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }


猜你喜欢

转载自blog.csdn.net/java_yes/article/details/83864042
今日推荐