揮発性のテストはアトミックではありません。揮発性を同期して追加する必要がありますか?sysnchronizedを追加する場合、volatileを追加する必要がありますか?

sysnchronizedを使用してvolatileを追加していますか?

/**
 * 测试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の値を取得する必要があります。揮発性を追加する場合、可視性は保証できますが、原子性は保証できないため、安全ではありません。
安全性を確保するために、メソッドに同期して追加する必要があります原子性を確保するため

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

    }

このようにして得られた値は10000であり、安全です。

sysnchronizedを追加する場合、volatileを追加する必要がありますか?

再確認後、揮発性物質を追加する必要がありますか?
答えは「はい」です。これは通常は検出できませんが、volatileを追加しないと、命令の並べ替えの問題が発生します。instance = new instanse()の場合、このオブジェクトはコンパイラによってコンパイルされ、命令は3つのステップに分割されます
。1。命令のメモリを要求する
2.メンバー変数を初期化する
3.このメモリをインスタンスに割り当てる
命令が3番目のステップを実行する場合まず、このオブジェクトはまだ作成されていませんが、別のスレッドがインスタンスが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();


        }


    }
}

揮発性で同期化されたものを追加するのは面倒ですが、他の方法はありますか?
はい、cas操作を通じてスレッドセーフを実現できます。
詳細については、ブログの別のcasロックフリー最適化、スピンロック、およびAtomicクラスを参照してください

おすすめ

転載: blog.csdn.net/yanfei464486/article/details/112511803