volatile关键字

发布时间 2023-11-24 18:53:50作者: 于辰文

volatile关键字

  • 特点:

  • 内存语义:

    • 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值立即刷新回主内存中
    • 当读一个volatile变量时,JMM会把该线程对应的本地内存设置为无效,重新回到主内存中读取最新共享变量的值

    所以volatile的写内存语义是直接刷新到主内存中,读的内存语义是直接从主内存中读取

单例模式

//https://www.cnblogs.com/luonote/p/10347427.html
//饿汉式:
class Singleton {
    // 1.私有化构造器
    private Singleton() {
    }
    // 2.内部提供一个当前类的实例
    // 4.此实例也必须静态化
    private static final Singleton single = new Singleton();
    //饿汉式单例在new对象时为什么不需要加volatile?
    //https://www.zhihu.com/question/453028971/answer/2112832011

    // 3.提供公共的静态的方法,返回当前类的对象
    public static Singleton getInstance() {
        return single;
    }
}
//懒汉式:
class Singleton {
    // 1.私有化构造器
    private Singleton() {

    }
    // 2.内部提供一个当前类的实例
    // 4.此实例也必须静态化
    private volatile static Singleton single = null;//volatile防止指令重排序

    // 3.提供公共的静态的方法,返回当前类的对象
    public static Singleton getInstance() {
        if(instance == null){//效率更高
            synchronized(Singleton.class){//同步锁
                if(instance == null){
                    instance = new Singleton();//初始化和赋值可能重排序
                } 
            }
        }
        return instance;
    }
}

//在方法上加同步锁,效率低
class Singleton {
    private Singleton() {
    }

    private static Singleton instance = null;

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

//使用InstanceHolder
class Singleton {
    private Singleton() {
    }

    private static final class InstanceHolder {
        static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return InstanceHolder.instance;
    }
}

CAS和原子类

public class AtomicClassTest {
    public static void main(String[] args) throws InterruptedException {
        IncreaseInteger val = new IncreaseInteger();
        System.out.println(val.get());

        new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                val.increase();
            }
        }).start();

        new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                val.increase();
            }
        }).start();

        Thread.sleep(1000);
        System.out.println(val.get());
    }
}

//原子类 ✓
class IncreaseInteger{
    private AtomicInteger value = new AtomicInteger(1);

    public void increase(){
        value.incrementAndGet();
    }

    public Integer get(){
        return value.get();
    }
}

//volatile + 锁 ✓
class IncreaseInteger{
    private volatile Integer value = 1;//保证可见性

    public synchronized void increase(){//保证原子性
        value++;
    }

    public Integer get(){
        return value;
    }
}
//并发会出现问题
class IncreaseInteger {
    private Integer value = 1;

    public void increase() {
        value++;
    }

    public Integer get() {
        return value;
    }
}