欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

验证volatile不保证原子性

程序员文章站 2024-03-22 09:19:16
...
验证volatile不保证原子性
*      原子性:完整性,不可分割性。某个线程在做某个业务时,不可以被加塞或被分割,需要整体完成,要么同时成功,要么同时失败。
*      volatile不保证原子性原因:i++,实际上分为4步,取值,+,更新主物理内存;volatile不保证更新主物理内存时,线程竞争存在覆盖重写,丢数据。
*      解决方法:1 使用synchronized (大材小用) 2 使用juc下的 AtomicInteger(原子……)

代码:

class MyData{
    //int number = 0 ;
    volatile int number = 0 ;
    public void setTo60(){
        this.number = 60;
    }
    //此时number前加volatile修饰,但是不保证原子性
    public void addPlusPlus(){
        number ++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();
    public void addMyAtomic(){
        atomicInteger.getAndIncrement();
    }
}
/**
 * 1 验证wolatile可见性
 * 2 验证wolatile不保证原子性
 *      原子性:完整性,不可分割性。某个线程在做某个业务时,不可以被加塞或被分割,需要整体完成,要么同时成功,要么同时失败。
 *      volatile不保证原子性原因:i++,实际上分为4步,取值,+,更新主物理内存;volatile不保证更新主物理内存时,线程竞争存在覆盖重写,丢数据。
 *      解决方法:1 使用synchronized (大材小用) 2 使用juc下的 AtomicInteger(原子……)
 * 3 验证wolatile禁止重排
 */
public class VolatileDemo {
    public static void main(String[] args){
        //seeOkByVolatile();
        final MyData myData = new MyData();
        for (int i =1;i<=20;i++) {
            final Thread aa = new Thread() {
                @Override
                public void run() {
                    for (int j = 1; j<= 2000; j ++) {
                        myData.addPlusPlus();
                        myData.addMyAtomic();
                    }
                };
            };
            aa.start();
        };
        //两个线程  主线程 和 垃圾回收线程
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        //number 永远《=40000;atomicInteger=40000 因为更新主内存时覆盖值原因,丢失值。
        System.out.println(Thread.currentThread().getName()+" final number is " + myData.number + "; final AtomicInteger is " + myData.atomicInteger);

    }

}