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

测试volatile不具有原子性,加volatile还用加sysnchronized吗?加sysnchronized还用加volatile吗?

程序员文章站 2022-05-28 17:06:10
...

加volatile还用加sysnchronized吗

/**
 * 测试volatile不具有原子性
 */
public class T {
    volatile int count=0;  //属性上加volatile 保证可见性

    public void sumCount(){ 
        for (int i = 0; i <1000 ; i++) {
            count++;  //count++操作在底层是好几步来实现,它本身不是一个原子性的操作
        }

    }

    public static void main(String[] args) {
        T t=new T();

        List<Thread> threads=new ArrayList<>();


        for (int i = 0; i <10 ; i++) {
         threads.add(new Thread(() ->{
             t.sumCount();
            }));
        }

        threads.forEach((o)->{
            o.start();
        });

        threads.forEach((o)->{
            try {
                o.join();  //保证main线程到当前线程执行完成后再执行
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println(t.count);


        //理论上应该得到的值是10000,在加volatile的情况下,虽然它能保证可见性,但是不能保证原子性,
        //所以的到的结果不对,在方法上加synchronized来保证原子性就安全了




    }


}

理论上应该得到的值是10000,在加volatile的情况下,虽然它能保证可见性,但是不能保证原子性,所以也是不安全的
为了保证安全,需要在方法上加synchronized保证原子性

 public synchronized void sumCount(){  //方法上加synchronized保证原子性
        for (int i = 0; i <1000 ; i++) {
            count++;  //count++操作在底层是好几步来实现,它本身不是一个原子性的操作
        }

    }

这样得到的值是10000,保证安全

加sysnchronized还用加volatile吗

双重检查完了,要不要加volatile呢?
答案是肯定的,虽然这个一般测不出来,但是不加volatile会出现指令重排序的问题!instance=new instanse()这个对象在编译器编译的时候指令分为三步:
1.给指令申请内存
2.给成员变量初始化
3.把这块内存赋值给instance
假如指令先执行了第三步,那么这个对象正在还没有创建出来,但是另一个线程过来一看,instance不是null,就不会走加锁的那段代码,直接来用这个对象,可是这个对象是个半初始化的对象,这样的话就会出问题了

/**
 * 懒汉模式4 -双重加锁
 *
 */
public class Singleton05 {
    private volatile static Singleton05 singleton05;  //需要加VOLATILE禁止指令重排序

    private Singleton05() {
    }

    public static Singleton05 getInstance() throws InterruptedException {

        if (singleton05 == null) {
            //加双重判断
            synchronized (Singleton05.class){
                if(singleton05==null){
                    Thread.sleep(1);
                    singleton05 = new Singleton05();

                }

            }

        }
        return singleton05;

    }

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

        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                try {
                    System.out.println(Singleton05.getInstance().hashCode());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();


        }


    }
}

加volatile还加sysnchronized好麻烦,能不能有别的办法呢?
有的,我们可以通过cas操作来实现线程安全
详见我博客另一篇
cas无锁优化,自旋锁 ,Atomic类

相关标签: java java

上一篇: Pymongo使用

下一篇: struts2拦截器