数据的原子性

版权声明:Please make the source marked https://blog.csdn.net/qq_31807385/article/details/83997108

先看下面的案例:

package hello_java;

public class Automic {
    public static void main(String[] args) throws InterruptedException {
        ShareData03 shareData03 = new ShareData03();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareData03.produce();
            }
        },"A");
        thread1.start();

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                shareData03.consume();
            }
        },"B");

        thread2.start();
        thread1.join();
        thread2.join();

        System.out.println("count 的值为:" + shareData03.count);
    }
}

class ShareData03{
    public int count = 0;
    public void produce(){
        count ++;
    }
    public void consume(){
        count --;
    }
}

count 的值为:0

现在我们把循环的的值从10 改到100000,(可以改的更大,这样效果更佳明显,错误也更容易出现)。

count 的值为:-1956

为什么会 出现这样的错误呢?

++ 和 -- 操作不是原子性的,中间可能会 被其他的指令打断。

关于这一点,可以参考下面的这个blog:

i++的底层解释

好的,接下来我们说说这个问题的解决方法:

package hello_java;

import java.util.concurrent.atomic.AtomicInteger;

public class Automic {
    public static void main(String[] args) throws InterruptedException {
        ShareData03 shareData03 = new ShareData03();
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                shareData03.produce();
            }
        },"A");
        thread1.start();

        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                shareData03.consume();
            }
        },"B");

        thread2.start();
        thread1.join();
        thread2.join();

        System.out.println("count 的值为:" + shareData03.count);
    }
}

class ShareData03{

    public AtomicInteger count = new AtomicInteger(0);
    public void produce(){
        count.incrementAndGet();
    }
    public void consume(){
        count.decrementAndGet();
    }
}


count 的值为:0

这个解决的方法是在jdk1.5之后在juc中出现的很多的原子类中的一个,这些原子类都使用了CSA算法。其中的

incrementAndGet  和  decrementAndGet 的源码我们打开看看,其使用了CSA:更底层使用的是 compareAndSwapInt ( CAS算法)

该算法会不断的轮询()循环),以获得最新的数据值。如下图:

猜你喜欢

转载自blog.csdn.net/qq_31807385/article/details/83997108