JAVA多线程(5):原子变量和CAS

一、原子变量

1.多线程++操作由于非原子变量导致问题

(1)预期

10个线程访问内部变量serialNumber,并进行serialNumber++操作。理论上serialNumber应当直接从0到10,但是结果和预期不符。

(2)代码

package thread.threadpool;

public class AtomicDemo {

    public static void main(String[] args) {
        AtomicTest at=new AtomicTest();
        for (int i = 0; i < 10; i++) {
            new Thread(at).start();
        }

    }

}

class AtomicTest implements Runnable{
    private int serialNumber;

    @Override
    public void run() {

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":"+getSerialNumber());
    }

    public int getSerialNumber() {
        return serialNumber++;
    }
}

结果:出现了3个0,而且最终到达7,而不是10.

Thread-4:0
Thread-8:0
Thread-9:7
Thread-0:2
Thread-7:1
Thread-3:3
Thread-1:4
Thread-2:0
Thread-6:6
Thread-5:5

2.导致问题原因

(1)serialNumber ++操作步骤分三步:“读-改-写“

int temp= serialNumber; //从主内存中读取
serialNumber = serialNumber+1;//修改,然后,写入主内存

(2)两个线程同时读取,并且修改可能会同时读取同一个值。
然后写入的是针对读取的同样的值进行处理的结果。

3.解决问题方法:采用原子变量

(1)原子变量包:package java.util.concurrent.atomic;
(2)原子变量特性:所有原子变量都具有内存可见性(被volatile关键字修饰)。同时,具有原子性(通过CAS算法保证)


二、CAS(Compare And Swap算法)

1.CAS是硬件对于并发操作共享数据的支持。

2.CAS操作

(1)包含三个变量:主内存值V,预估值A,更新值B
(2)首先,读取主内存值V。
然后,在操作该变量后,准备重新写入的时候,重新读取一下主内存中值A,比较A和V。
最后,当且仅当V==A的时候,把B赋值给V,否则不进行任何操作。

3.CAS解决原子性问题

上图的原子性问题,可以通过CAS解决如下


4.具体代码:原子变量AtomicInteger

package thread.threadpool;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicDemo {

    public static void main(String[] args) {
        AtomicTest at=new AtomicTest();
        for (int i = 0; i < 10; i++) {
            new Thread(at).start();
        }
    }
}

class AtomicTest implements Runnable{
    private AtomicInteger serialNumber;

    @Override
    public void run() {

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":"+getSerialNumber());
    }

    public int getSerialNumber() {
        return serialNumber.getAndIncrement();
    }


}

结果:

Thread-5:0
Thread-1:3
Thread-0:2
Thread-4:1
Thread-2:4
Thread-3:7
Thread-8:6
Thread-9:5
Thread-6:8
Thread-7:9


 

发布了453 篇原创文章 · 获赞 133 · 访问量 24万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 撸撸猫 设计师: 设计师小姐姐

分享到微信朋友圈

×

扫一扫,手机浏览