VarHandle:Java9中保证变量读写可见性、有序性、原子性利器

news2024/10/2 6:30:38

文章目录

  • 一、什么是VarHandle
    • 0、JMM
    • 1、jdk9之前无锁技术的实现
  • 二、VarHandle使用
    • 1、VarHandle 快速上手
    • 2、VarHandle常用方法
    • 3、实战案例1:解决可见性(比volatile轻量)
    • 4、实战案例2:解决指令重排序(比volatile轻量)
      • (1)案例分析: partial ordering
      • (2)案例分析:total ordering

一、什么是VarHandle

0、JMM

JMM内存模型深入详解,探索volatile、synchronized与VarHandle深层次的奥秘

1、jdk9之前无锁技术的实现

JDK9之前, Java 中的无锁技术主要体现在以 AtomicInteger 为代表的的原子操作类,它的底层使用 Unsafe 实现,而Unsafe 的问题在于安全性和可移植性。

此外,volatile 主要使用了 Store-Load 屏障来控制顺序,这个屏障还是太强了,有没有更轻量级的解决方法呢?

二、VarHandle使用

1、VarHandle 快速上手

在 Java9 中引入了 VarHandle,来提供更细粒度的内存屏障,保证共享变量读写可见性、有序性、原子性。提供了更好的安全性和可移植性,替代 Unsafe 的部分功能。

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;

public class TestVarHandle {
	int x; // 共享变量
	static VarHandle X; // 共享变量的操作对象 VarHandle 的创建比较耗时,所以最好不要重复创建
	
	static {
		try {
		    // 初始化VarHandle :需要指定要保护的变量,某个类中的 共享变量名名 共享变量类型
			X = MethodHandles.lookup()
					.findVarHandle(TestVarHandle.class, "x", int.class);
		} catch (NoSuchFieldException | IllegalAccessException e) {
			e.printStackTrace();
		}
	}
	
    public static void main(String[] args) {
        TestVarHandle obj = new TestVarHandle();
        X.set(obj, 10); // 设置值
        Object o = X.get(obj); // 获取值
        System.out.println(o);
    }
}

2、VarHandle常用方法

在这里插入图片描述

3、实战案例1:解决可见性(比volatile轻量)

下面的实例,是一个经典案例,循环永远不会停止,具体原因此处就不分析了,就是因为可见性导致的。解决这个问题很简单,将stop用volatile进行标记就可以了。

// 永不终止的循环 - 可见性问题
public class TestInfinityLoop {
    static boolean stop = false; //停止标记

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stop = true; // volatile 的写
        });
        System.out.println("start " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
        t.start();
        foo();
    }

    private static void foo() {
        while (true) {
            boolean b = stop; // volatile 的读
            if (b) {
                break;
            }
        }
        System.out.println("end " + LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
    }
}


jdk9引入的VarHandle ,可以替换volatile,也可以实现共享变量的可见性问题:

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Date;

public class TestVarHandleOpaque {
    static boolean stop;

    static VarHandle STOP;

    static {
        try {
            STOP = MethodHandles.lookup()
                    .findStaticVarHandle(TestVarHandleOpaque.class, "stop", boolean.class);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (true) {
                if ((boolean) STOP.getOpaque()) {
                    break;
                }
            }
            System.out.println("quit " + new Date());
        }).start();

        System.out.println("start " + new Date());
        Thread.sleep(1000);
        STOP.setOpaque(true);
    }
}

4、实战案例2:解决指令重排序(比volatile轻量)

同样的,以下例子可以使用VarHandle解决指令重排序的问题:

import org.openjdk.jcstress.annotations.*;
import org.openjdk.jcstress.infra.results.II_Result;

@JCStressTest
@State
//             r1  r2
@Outcome(id = "1, 0", expect = Expect.ACCEPTABLE)
@Outcome(id = "0, 2", expect = Expect.ACCEPTABLE)
@Outcome(id = "1, 2", expect = Expect.ACCEPTABLE)
@Outcome(id = "0, 0", expect = Expect.ACCEPTABLE_INTERESTING)
public class Test4Possible {
    int a;
    int b;
    @Actor // 线程1
    public void action1(II_Result r) {
        a = 1;
        r.r2 = b;
    }
    @Actor // 线程2
    public void action2(II_Result r) {
        b = 2;
        r.r1 = a;
    }
}

public class TestVarHandle {
    /**
     * 案例1: 演示 VarHandle 可以用来解决 partial ordering 问题
     */
    @JCStressTest
    @Outcome(id = {"0, 1","0, 0","1, 1"}, expect = Expect.ACCEPTABLE, desc = "ACCEPTABLE")
    @Outcome(id = "1, 0", expect = Expect.FORBIDDEN, desc = "INTERESTING")
    @State
    public static class Case1{
        int x;
        int y;
        static VarHandle Y;
        static {
            try {
                Y = MethodHandles.lookup().findVarHandle(Case1.class, "y", int.class);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        @Actor
        public void actor1(II_Result r) {
            x = 1;
            Y.setRelease(this, 1);
        }

        @Actor
        public void actor2(II_Result r) {
            r.r1 = (int) Y.getAcquire(this);
            r.r2 = x;
        }
    }

    /**
     * 案例2: 演示 VarHandle 能解决 total ordering 的情况
     */
    @JCStressTest
    @Outcome(id = {"1, 0","0, 0","0, 1"}, expect = Expect.ACCEPTABLE, desc = "ACCEPTABLE")
    @Outcome(id = "1, 1", expect = Expect.FORBIDDEN, desc = "INTERESTING")
    @State
    public static class Case2{
        int x;
        int y;

        static VarHandle X;
        static VarHandle Y;
        static {
            try {
                X = MethodHandles.lookup().findVarHandle(Case2.class, "x", int.class);
                Y = MethodHandles.lookup().findVarHandle(Case2.class, "y", int.class);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        @Actor
        public void actor1(II_Result r) {
            r.r2 = (int) X.getAcquire(this);
            Y.setRelease(this, 1);
        }

        @Actor
        public void actor2(II_Result r) {
            r.r1 = (int) Y.getAcquire(this);
            X.setRelease(this, 1);
        }
    }


    /**
     * 案例3: 演示 VarHandle 不能解决 total ordering 的情况
     */
    @JCStressTest
    @Outcome(id = {"1, 0","1, 1","0, 1"}, expect = Expect.ACCEPTABLE, desc = "ACCEPTABLE")
    @Outcome(id = "0, 0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "INTERESTING")
    @State
    public static class Case3{
        int x;
        int y;

        static VarHandle X;
        static VarHandle Y;
        static {
            try {
                X = MethodHandles.lookup().findVarHandle(Case3.class, "x", int.class);
                Y = MethodHandles.lookup().findVarHandle(Case3.class, "y", int.class);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        @Actor
        public void actor1(II_Result r) {
            Y.setRelease(this, 1);
            r.r2 = (int) X.getAcquire(this);
        }

        @Actor
        public void actor2(II_Result r) {
            X.setRelease(this, 1);
            r.r1 = (int) Y.getAcquire(this);
        }
    }
}

(1)案例分析: partial ordering

case 1,如果 y=1 先发生,那么前面的 Store 屏障会阻止 x=1 排下去,而后面的 Load 屏障会阻止后续的 r.r2=x排上来
在这里插入图片描述
如果 y=1 后发生,那么 Store 屏障会阻止 x=1 排下去,而 Load 屏障会阻止后续的 r.r2=x 排上去,同样,无法控制 r.r2=x 和 x=1 的执行顺序(case 2 case 3)还有可能是 x=1 在 r.r1=y 之前,但结果与 case 3 相同
在这里插入图片描述
在这里插入图片描述

(2)案例分析:total ordering

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
case 4,注意看红色的屏障之间的代码仍然可以被重排、蓝色的也一样,因为 case 3 中,红色 Load 屏障只能阻止下面的代码上不来,Store 屏障只能阻止上面的代码下不去,但在此之间,代码顺序无法保证
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/788211.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3dsmax制作一个小人

文章目录 步骤起阶五官手臂短袖添加头发、头饰BodyPaint软件贴图导入到3dsmax 渲染 步骤 起阶 五官 手臂 短袖 添加头发、头饰 BodyPaint软件贴图 寻找网络贴图,用PS切割,用BodyPaint恢复纹理 导入到3dsmax 渲染

【干货防踩坑/全图文分步/Gitlab镜像仓库自动同步】Gitlab CE/EE镜像仓库的配置技巧(含ssh/密码两验证方法)

【干货踩坑】Gitlab CE/EE镜像仓库的配置技巧(含ssh/密码两验证方法) 众所周知,Gitlab是个好东西。为什么呢?GitHub没有的功能,他全有了。更何况还可以私有部署。这两天自己部署了Gitlab,然后想把自己的项…

springboot + redis + 注解 + 拦截器 实现接口幂等性校验

一、概念 幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。在计算机中编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。 幂等函数或幂等方法是…

【C++杂货铺】内存管理

文章目录 一、C/C内存分布二、C内存管理方式2.1 new和delete操作内置类型2.2 new和delete操作自定义类型 三、operator new与operator delete函数四、new和delete的实现原理4.1 内置类型4.2 自定义类型 五、定位new表达式(placement-new)六、malloc/free…

二十三种设计模式第十八篇--责任链模式

责任链模式是一种行为型设计模式,它允许你将请求沿着处理者链传递,直到有一个处理者能够处理该请求为止。责任链模式将请求发送者和请求处理者解耦,从而使得多个处理者都有机会处理同一个请求。 该模式包含以下几个关键角色: 抽象…

CUDA之指针篇

CUDA教程 第一章 指针篇 第二章 cuda原理篇 第三章 随着人工智能的发展与人才的内卷,很多企业已将深度学习算法的C部署能力作为基本技能之一。面对诸多arm相关且资源有限的设备,往往想更好的提速,满足更高时效性,必将更多类似矩…

【高危】Spring Security鉴权规则错误配置风险

漏洞描述 Spring Security 是一套为基于Spring的应用程序提供说明性安全保护的安全框架。 在 Spring Security 受影响的版本中,由于 Spring Security 的授权规则会应用于整个应用程序上下文,当应用程序中包含多个servlet,并且其中一个为Dis…

测试必备工具之抓包神器 Charles 如何抓取 https 数据包?

前言 之前我们发过一篇文章讲解了Charles抓包工具的基本使用,有需要的小伙伴可以去看上一篇文章。 之前文章讲的数据包主要是http协议,大家可以看到数据包并直接显示具体详细的内容: 但是如果抓到的是https的报文,是没有办法直…

Redis DeskTop Manager 使用教程

简单粗暴的介绍一下,以及在工作中如何去使用工具管理我们的Redis,更加详细及深入的使用方法欢迎大家评论区讨论,我也和大家一起学习。 简介: Redis Desktop Manager (RDM) 是一个开源的图形化 Redis 数据库管理工具,…

erp什么意思,erp系统软件到底是干嘛用的?

企业资源计划 (ERP) 的定义 企业资源计划 (ERP) 是指组织用于管理日常业务活动的一套软件,这些活动包括会计、采购、项目管理、风险管理和合规性、供应链运营等等。完整的 ERP 套件还包括企业绩效管理软件,用于帮助企业针对财务结果制定计划和编制预算…

react-native项目安卓版本升级 compileSdkVersion 29->31

因为 react-native-ble-manager添加过程及碰到的问题 依赖 https://github.com/innoveit/react-native-ble-manager 参考:https://blog.csdn.net/withings/article/details/71378562 iOS 按react-native-ble-manager 文档在 【Info.plist】加了key之后能正常使用…

Vue学习Day1——小案例快速入门Vue指令

一、Vue简介 概念:是一套 构建用户界面 的 渐进式 框架 Vue2官网:https://v2.cn.vuejs.org/ 1、什么是渐进式 所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点 Vue的两种开发方式&…

【图像分割】基于蜣螂优化算法DBO的Otsu(大津法)多阈值电表数字图像分割 电表数字识别【Matlab代码#51】

文章目录 【可更换其他算法,获取资源请见文章第5节:资源获取】1. 原始蜣螂优化算法1.1 滚球行为1.2 跳舞行为1.3 繁殖行为1.4 偷窃行为 2. 多阈值Otsu原理3. 部分代码展示4. 仿真结果展示5. 资源获取说明 【可更换其他算法,获取资源请见文章第…

UDS之27服务

SecurityAccess(0x27)—— 安全访问 这个服务的目的是为那些限制访问,以及和排放、安全相关的一些服务和数据提供一些访问权限来保护数据。 此服务执行步骤如下: (1)Client请求一个种子(Seed…

一.安装k8s环境

1.初始操作 默认3台服务器都执行 # 关闭防火墙 systemctl stop firewalld systemctl disable firewalld# 关闭selinux sed -i s/enforcing/disabled/ /etc/selinux/config # 永久 setenforce 0 # 临时# 关闭swap swapoff -a # 临时 sed -ri s/.*swap.*/#&/ /etc/fstab…

国标GB28181视频监控平台EasyGBS无法播放,抓包返回ICMP的排查过程

国标GB28181视频平台EasyGBS是基于国标GB/T28181协议的行业内安防视频流媒体能力平台,可实现的视频功能包括:实时监控直播、录像、检索与回看、语音对讲、云存储、告警、平台级联等功能。国标GB28181视频监控平台部署简单、可拓展性强,支持将…

【Docker】基本概念和底层技术

Docker 1 什么是 Docker Docker 是一种容器技术。只要开发者将其应用和依赖包进行打包,放入到一个轻量级的、可移植的容器中,就能发布到任何流行的 linux 机器上。 Docker 的要素: image 镜像:静态的container 容器&#xff1a…

多线程-synchronized

文章目录 synchronized同步方法synchronized同步静态方法synchronized同步代码块 Java的多线程允许同时做多件事情。但是,两个及两个以上的线 程彼此互相影响的问题也就出现了。如果不防范这种冲突,就可能发 生两个用户购买了同一个座位的火车票&#xf…

【Nodejs】nodejs内置模块(中)

1.路劲处理模块 path 1.1 模块概览 在nodejs中,path是个使用频率很高,但却让人又爱又恨的模块。部分因为文档说的不够清晰,部分因为接口的平台差异性。将path的接口按照用途归类,仔细琢磨琢磨,也就没那么费解了。 1.…

【Ruoyi】静态资源映射

这里写自定义目录标题 帮助链接核心代码分析 帮助链接 SpringBoot–WebMvcConfigurer详解Ruoyi自定义资源映射 核心代码 /*** 通用配置* * author wiserice*/ Configuration public class ResourcesConfig implements WebMvcConfigurer {Autowiredprivate RepeatSubmitInter…