猿问

Java多线程i++线程安全问题,volatile和AtomicInteger解释?

在Java多线程中,i++和i--是非线程安全的。

例子:


public class PlusPlusTest {


    public static void main(String[] args) throws InterruptedException {

        Num num = new Num();

        ThreadA threadA = new ThreadA(num);

        ThreadB threadB = new ThreadB(num);

        threadA.start();

        threadB.start();

        Thread.sleep(200);

        System.out.println(num.count);

    }

}


class ThreadA extends Thread {

    private Num num;


    public ThreadA(Num num) {

        this.num = num;

    }


    @Override

    public void run() {

        for (int i = 0; i < 1000; i++) {

            num.count++;

        }

    }

}


class ThreadB extends Thread {

    private Num num;


    public ThreadB(Num num) {

        this.num = num;

    }


    @Override

    public void run() {

        for (int i = 0; i < 1000; i++) {

            num.count++;

        }

    }

}


class Num {

    int count = 0;


    public Num() {

    }

}

以上代码输出结果基本上不是2000,会比2000小。


原因:


在线程A中,i++的过程为:

temp1 = i; temp2 = temp1 + 1; i = temp2;

在线程B中,i++的过程为:

temp3 = i; temp4 = temp3 + 1; i = temp4;


在i=0的时候,线程A和B同时读取i=0。

线程A执行++后,i被修改成1。

线程B执行++后,i被修改,但还是1。


问:这样的解释对么?




想到把count变量申明为volatile,但是:


即使把count申明为volatile,输出的结果也不是2000,请问为什么?


class Num {

    volatile int count = 0;


    public Num() {

    }

}



最后


把count变量包装成AtomicInteger之后,输出的结果为2000,正确,这又是为什么?


子衿沉夜
浏览 918回答 4
4回答

料青山看我应如是

因为volatile不保证操作的原子性,i++这种操作并不是原子操作。

慕的地8271018

volatile只能保证可见性,即别人修改了之后你立马能读到,但是你改的时候别人也可以改。AtomicInteger是基于CAS(Compare And Swap)的。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。 两个问题: (1)CAS算法仍然可能会出现冲突,例如A、B两个线程,A已经进入写内存但未完成,此时A读取到的副本且读取成功,AB两个线程同时进入写内存操作,必然会造成冲突。 CAS算法本质并非完全无锁,而是把获得锁和释放锁推迟至CPU原语实现,相当于尽可能的缩小了锁的范围;直接互斥地实现系统状态的改变,它的使用基本思想是copy-on-write——在修改完对象的副本之后再用CAS操作将副本替换为正本。 (2)ABA问题,若其中一个线程修改A->B->A,另外一个线程仍然读取到A,虽然值是预期值,但并不能说明该内存值没有变化。

慕慕森

懒的写答案了,给一个非常好的文章Java并发编程:volatile关键字解析

慕桂英4014372

volatile保证每次得到的数据是最新的(从内存中读取),i++; --> i=i+1; 如果执行到i+1没有赋值给i的话,就无法保证另个线程得到的数据是最新的,后面那个是原子操作,所以能够保证i=这一定会执行
随时随地看视频慕课网APP

相关分类

Java
我要回答