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

加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类

猜你喜欢

转载自blog.csdn.net/yanfei464486/article/details/112511803