Vavr中Lazy类基于volatile supplier的双重检查锁定为何线程安全
关于Vavr Lazy实现的线程安全性解答
这段代码完全符合JSR-133内存模型规范,不存在你担心的半初始化对象逃逸问题,核心逻辑如下:
- 首先明确
get()方法的执行逻辑:只有当读supplier(volatile变量)的结果为null时,才会直接读取value返回,否则都会进入同步方法computeValue。 - 我们先看
computeValue内部的重排序约束:给supplier赋值null是volatile写操作,根据JMM重排序规则,volatile写之前的所有读写操作(包括s.get()内部的对象初始化、给value赋值的操作),都不允许被重排序到volatile写之后。也就是说,必须等对象完全初始化、value赋值完成后,才会执行supplier = null的操作。 - 再看读侧的可见性保障:根据JMM的happens-before规则,对volatile变量的写操作,happen-before于后续对这个变量的读操作。也就是说,当其他线程在
get()中读到supplier == null时,写supplier之前的所有操作(对象初始化、value赋值)对当前线程都是可见的,此时读到的value一定是完全初始化后的对象。 - 你担心的对象初始化和
value赋值的重排序问题,并不会导致半初始化对象逃逸:因为这种重排序只会发生在supplier被置为null之前,此时其他线程读supplier的结果都是非null,会进入同步方法computeValue,而computeValue被synchronized修饰,同一时间只有一个线程能进入,其他线程会阻塞等待首个执行线程完成初始化、将supplier置为null后才会继续执行,不会出现直接读取半初始化value的场景。
你提到的注释中说
value表现得像volatile,本质就是依赖volatile读写的happens-before规则,把对value的读写和supplier的volatile读写绑定,从而获得可见性和有序性保障。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

