Java基础:Java内存模型

Java内存模型(Java Memory Model,JMM) 关于面试刷题也是有方法可言的,建议最好是按照专题来进行,然后由基础到高级,由浅入深来,效果会更好。Java基础部分算法与编程数据库部分流行的框架与新技术(Spring+SpringCloud+SpringCloudAlibaba)这份面试文档当然不止这些内容,实际上像JVM、设计模式、ZK、MQ、数据结构等其他部分的面试内容均有涉及,因为文章篇幅,就不全部在这里阐述了。 阅读详情

        Java内存模型是一种抽象的规则或规范,定义了程序中存在竞争现象的对象(包括实例字段、静态字段和数组对象,不包括局部变量,形式参数;后者是线程私有,不存在竞争问题)的访问方式。

        如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。

        JVM通过Java内存模型,屏蔽掉不同硬件和操作系统的内存访问差异,实现各种平台具有一致的并发效果。

1. 内存模型

1.1 硬件的效率与一致性——计算机内存模型

​

        显然,CPU的运行速度远远大于内存交互速度,至少有这几个数量级的差距。因此,现代计算机在CPU与内存之间都有一个高速缓存(Cache)作为数据缓冲:将运算需要的数据从内存中复制到缓存中,当缓存从CPU中拿到运算结果之后再同步到内存中——这样CPU就不用等待缓慢的内存读写了。

        但此时就出现了一个大问题:缓存一致性。 现在基本都是多核处理器,每个处理器都有自己的高速缓存,而他们共享同一个主内存,这样就会导致各自的缓存数据不一致的情况,为了解决这个问题各个处理器访问缓存时都要遵循一些协议,在读写时要根据协议来进行操作,这类协议有MSI、MESI、MOSI、Synapse等等。 除此之外,为了使得处理器内部的运算单元能尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果是一致的,但并不保证程序中各个语句计算的先后顺序与输入代码中的顺序一致。类似的,Java虚拟机的即时编译器中也有类似的指令重排序优化。

1.2 Java内存模型

接下来,我们通过一个Java程序了解缓存一致性。

Java的内存模型跟计算机的内存模型极其相似

​

        CPU在内存模型当中充当的就是“算术逻辑单元”,主要负责运算。 Java线程也可以理解为“运算单元”,因此,可以看到,Java内存模型几乎和计算机内存模型保持一致。

内存模型总述

  • 1.所有变量都在主内存当中,工作内存中的变量都是从主内存中拷贝的。

  • 2.线程对变量的所有操作都在工作内存中完成

  • 3.不同线程无法直接访问其他线程工作内存中的变量。线程之间的变量传递需要通过主内存完成

Java中的缓存一致性问题: . 考虑下面这个代码: i = 10++; 假设现在有两个线程同时执行上述代码, 根据内存模型总述第1条,这两个线程都是从主内存中拷贝i到自己的工作内存当中,然后分别对其执行自加,然后将其放回主内存。 此时,尽管“自加了两次”,但实际上i=11,而非12。 这种被多个线程访问的变量为共享变量。

1.3 Java内存模型和计算机内存模型的关系

通常情况下,当一个cpu需要读取主存的时候它会将主存的部分读取到cpu缓存中。它甚至会将缓存的部分内容读到内部寄存器里,然后在寄存器中执行操作,当cpu需要将结果回写到主存的时候,它会将内部寄存器的值刷新到缓存中,然后在某个时间点将值刷新回主存。

​

Heap就是主内存,Thread Stack就是工作内存

        通过图可以看出java内存模型与硬件架构之间存在一些差异,硬件内存架构它没有区分线程栈和堆,对于硬件而言所有的线程栈和堆都分布在主内存里,部分cpu栈和堆可能出现cpu缓存中和cpu内部的寄存器里面。

2. 内存特性

2.1 原子性

一个操作是不可中断的,即便是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。

对基本数据类型的变量读取和赋值的操作都是原子操作,即这些操作是不可中断,要么执行,要么不执行。

x = 10;         //语句1
y = x;         //语句2
x++;           //语句3
x = x + 1;     //语句4

以上语句只有语句1是原子性操作。

  • 语句1是直接将数值10赋值给x,也就是说线程执行这个语句会直接将数值10写入到工作内存中。

  • 语句2实际上包含2个操作,先读取x的值,再将x的值写入到工作内存中,虽然读取x的值及将x的值写入工作内存都是原子操作,但结合起来就不是原子性的操作了。

  • x++和x=x+1包含3个操作,读取x的值,进行加1操作,写入新的值。

  • 也就是说,只有简单的读取、赋值(而且必须是将数字赋值给某个变量,变量之间的相互赋值不是原子操作)才是原子操作。

        Java内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和Lock来实现。由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。

2.2 有序性

        编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。 也就是说:在并发时,程序的执行可能会出现乱序。

        另外,Java内存模型具备一些先天的“有序性”,即不需要通过任何手段就能够得到保证的有序性,这个通常也称为 happens-before 原则。如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序。

2.3 可见性

        一个线程修改了某一个共享变量的值,其他线程是否能够立刻知道这个修改。(可见会牺牲性能)。

        通过volatile关键字保证可见性:

  • 当一个共享变量被volatile修饰时,它会保证修改的值会立即更新到主存,当有其他线程需要读取时,它会去主存中读取最新的值。

普通的共享变量不能保证可见性,因为共享变量被修改后,什么时候被写入主存是不确定的,当其他线程去读取的时候,此时内存中可能还是原来的旧值,因此无法保证可见性。 通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。

2.4 Happen-Before 规则

  • 程序顺序原则:一个线程内保证语义的串行性(按书写次序顺序执行)

  • 锁规则:解锁必然发生在随后的加锁前

  • 传递性:A 先于 B ,B 先于 C,那么 A 必然先于 C

  • volatile 规则:volatile 变量的写,先发生于读,保证了 volatile 变量的可见性

  • 线程启动规则:线程的 start() 方法先于它的每一个动作

  • 线程中断规则:线程的所有操作先于线程的终结(Thread.join())

  • 线程终结规则:线程的中断先于被中断程序的代码

  • 对象终结规则:对象的构造函数执行结束先于 finalize() 方法

        如果不满足以上规则,则虚拟机就会对其进行指令重排序

指令重排序

        在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序,重排序分为以下三种类型

1、编译器优化的重排序--编译器在不改变单线程程序语义的情况下,可以重新安排语句的执行顺序

2、指令级并行的重排序--如果不存在数据依赖,处理器可以改变语句对应机器执行的语句顺序

3、内存系统的重排序--由于处理器使用缓存和读/写缓存,这使得加载和存储操作看上去像是在乱序执行

        在执行程序时,java内存模型确保在不同的编译器和不同的处理器平台上,来插入内存屏障来禁止特定的编译器重排序和处理器重排序,从而为上层提供内存一致性的条件。

3. 内存同步(交互)的八大操作

        关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了以下八种操作来完成:

  • lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占的状态。

  • unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

  • read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。

  • load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。

  • use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎。(每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作)

  • assign(赋值):作用于工作内存的变量,它把一个执行引擎接收到的值赋值给工作内存的变量。(每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作)

  • store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。

  • write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

同步规则

  • 1、如果要把一个变量从主内存中复制到工作内存,就需要按顺序地执行read和load操作,如果把变量从工作内存中同步回主内存中,就要按顺序地执行store和write操作。但java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。

  • 2、不允许read和load、store和write操作之一单独出现

  • 3、不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。

  • 4、不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。

  • 5、一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。

  • 6、一个变量在同一时刻只允许一条线程对其进行locd操作,但lock操作可以被同一条线程重复执行多次,多次执行load后,只有执行相同次数的unlock操作,变量才会被解锁。lock和unlock必须成对出现。

  • 7、如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行Load或assign操作初始化变量的值。

  • 8、如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。

  • 9、对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。

Java学习视频分享

Java基础:

Java300集,Java必备优质视频_手把手图解学习Java,让学习成为一种享受

Java项目:

【Java游戏项目】1小时教你用Java语言做经典扫雷游戏_手把手教你开发游戏

【Java毕业设计】OA办公系统项目实战_OA员工管理系统项目_java开发

JVM内存模型 Java内存模型 Java内存模型是共享内存的并发模型,线程之间主要通过读-写共享变量(堆内存中的实例域,静态域和数组元素)来完成隐式通信。 Java 内存模型(JMM)控制 Java 线程之间的通信,决定一个线程对共享变量的写入何时对另一个线程可见。 计算机高速缓存和缓存一致性 计算机在高速的 CPU 和相对低速的存储设备之间使用高速缓存,作为内存和处理器之间的缓... 阅读详情

相关推荐

Java内存模型-清晰剖析

Java 内存模型(JMM)指定了Java 虚拟机(JVM)如何与计算机内存RAM) 配合使用。由于Java虚拟机与内存交互的时候,是通过Java线程去做的,因此Java内存模型其实就是针对Java的线程模型进行研究的,因此Java内存模型其实也叫“Java线程模型。Java 内存模型(JMM) 控制Java 中的线程如何与内存交互。它保证一个线程所做的更改对其他线程可见,即Java 内存模型(JMM) 可以指定不同线程如何以及何时可以看到其他线程写入共享变量的值,从而为安全的多线程提供框架。

在技术的广袤天地里,本博客如精准罗盘。剖析前沿科技,深掘代码奥秘,以精炼笔触,带您穿越复杂技术迷宫,速达知识彼岸。 2916

Java内存模型

从Java代码到CPU指令的变化过程是怎样的?最开始,我们编写的Java代码,即*.Java文件在执行编译Javac命令后,从刚才的*.Java文件会变出一个新的Java字节码文件,即*.class文件JVM会执行刚才生成的*.class字节码文件,并把字节码文件转化为机器指令机器指令可以直接在CPU上执运行,也就是最终的程序执行。

Qynwang的博客 3953

【windows】【系统还原】亦是美kms执行一键关闭defender 之后,windows defender 被卸载了,无论如何都打不开

还是执行 都没有明显效果 那么,我最后是怎么解决得呢? 一、打开控制面板(任务栏搜索kzmb)

weixin_41899098的博客 6908

深入理解Java内存模型(JMM)与虚拟机的内存结构(JVM)

在Java编程世界中,Java内存模型(Java Memory Model,简称JMM)和Java虚拟机(Java Virtual Machine,简称JVM)的内存结构是两个核心概念。它们对于理解Java程序的执行方式、性能优化以及并发编程至关重要。尽管这两个概念紧密相连,但它们的职责和特性却各不相同。本文将详细探讨Java内存模型与Java虚拟机的内存结构,帮助读者更深入地理解它们之间的关系和差异。

码到三十五 1万+

Win11 1 月更新黑屏循环故障技术分析与解决方案

2026年1月30日Windows 11更新引发黑屏循环故障,主要影响2018年前出厂、采用MBR分区及特定BIOS固件的设备,尤其对使用经典版Outlook(POP协议)的用户影响显著。故障表现为系统无限重启黑屏,导致数据访问中断。分析表明,问题源于硬件兼容性、分区格式与系统更新的交互冲突。解决方案包括进入安全模式回滚更新、暂停自动更新、升级驱动/BIOS,以及等待微软官方补丁。建议用户更新前评估硬件兼容性并备份数据,企业环境应建立分阶段更新测试机制。该事件为系统更新风险管理提供了重要参考。

博客 1442

Vue3 - [最强] 超详细 Element Plus 组件库主题颜色进行 “统一全局“ 替换,将默认的蓝色主题色更换为其他自定义颜色,覆盖原来的主题色改为自己的颜色(完美解决主题色不生效、没反应)

elementplus修改主题色,vue3+element-plus主题色更换,vue3vite如何修改扩展elementplus主题色样式,全局设置elementplus主题色,有什么办法可以直接全局修改主题色,对elementplus默认蓝色不满意怎么替换更改其他颜色,elementplus覆盖默认主题色,elementplus主题色官方文档,vue3中修改elementplus主题色,elementplus修改主题色不生效怎么办,elementplus如何修改主题颜色,eleme

🏆 前端领域优质创作者 1万+

关于 java:8. Java 内存模型与 JVM 基础

类加载器负责加载类的字节码,并生成 Class 对象。JVM 中类由类加载器标识,类名 + 加载器才能唯一确定一个类。所以:两个类名相同但由不同 ClassLoader 加载,它们是两个不同的类。@Override// 你自定义的加载逻辑可用于加密类解密、插件隔离、JVM内存马注入等。

Triste__chengxi的博客 4446

FFMPEG音频开发: Linux下采集摄像头(使用V4L2框架)数据录制成MP4视频保存到本地

一、环境介绍 操作系统介绍:ubuntu 18.04 FFMPEG版本: 4.4.2 摄像头: USB摄像头、虚拟机挂载本机自带摄像头 二、FFMPEG与X264下载编译 X264下载地址: http://www.videolan.org/developers/x264.html FFMPEG下载地址:https://ffmpeg.org/download.html Yasm ...

8872

JVM第七讲:JVM 基础 - Java 内存模型详解

本文是JVM第七讲,JVM 基础 - Java 内存模型详解。主要转载自 Info 上[深入理解Java内存模型](https://www.infoq.cn/article/java_memory_model/), 作者程晓明。这篇文章对JMM讲的很清楚了,大致分三部分:1、重排序与顺序一致性;2、三个同步原语(lock,volatile,final)的内存语义,重排序规则及在处理器中的实现;3、java 内存模型的设计,及其与处理器内存模型和顺序一致性内存模型的关系。

Jet_qi的博客 489

视图库对接系列(GA-T 1400)一、简单介绍

GA/T 1400《公安视频图像信息应用系统》 是我们需要参考看看的相关文档,里面有对应的标准和介绍,没有这个文档的话可以加群找我要。群的话 我放在最下面了。我们先简单想几个问题, 也就是这个协议主要干什么用的,为什么要有, 能做什么。

qq_37716298的博客 4288

STM32入门教程:WiFi通信

第四步:初始化串口 在生成的代码中,您可以找到一个名为 "USARTx_Init" 的函数,其中 "x" 是您选择的串口号。然后,我们使用 "AT+CIPSEND" 命令发送UDP数据,接收到服务器的回复,并在终端上显示收到的数据。在配置向导中,您可以选择启用USART串口功能,并根据您的硬件连接,将串口设置为与WiFi模块连接的串口。在上述代码中,我们使用了 "HAL_UART_Receive" 函数来接收串口数据,并使用 printf 来在终端上显示收到的数据。如果有任何问题,请随时向我提问。

2401_85258012的博客 1074

Java基础:内存模型

  在java基础当中,有很重要一块的内容,就是关于java当中的内存模型,所涉及的问题无非就是关于java当中的类、实例、变量、常量、静态变量、方法等blabla的东西都分别存储在什么地方。这部分的内容虽然繁琐,但是也是面试当中经常涉及询问的部分,今天就在这里总结一下java当中的内存模型。   首先我们来看一下java的内存模型大体分为了几个部分: 从图片当中可以看到,jav...

148

Nvidia Orin Driveos Camera 介绍及调试详解

自动驾驶-nvidia orin driveos Camera 驱动详解及调试

u011803281的博客 2992

Java内存模型深度解析:基础部分

码农网:http://www.codeceo.com/article/java-memory-1.html 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体)。通信是指线程之间以何种机制来交换信息。在命令式编程中,线程之间的通信机制有两种:共享内存和消息传递。 在共享内存的并发模型里,线程之间

面朝大海,春暖花开 614

【系统分析师】核心考点:100个高频知识点汇总

本文系统梳理了系统分析师考试的11大领域高频考点,重点解析了计算机硬件与体系结构的7个核心知识点:计算机五大部件(CPU/存储器/总线等)、校验码类型(奇偶/海明/CRC)、CISC与RISC指令系统对比、总线分类与特性、RAID磁盘阵列级别、流水线技术原理及Flynn系统分类法。内容涵盖硬件组成、数据校验、指令架构、存储技术等关键概念,通过表格对比和公式说明,为考生提供结构化的知识框架与备考重点。

数据知道的博客 5569

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

十分钟看Java基础:Java内存模型

文章目录一、 Java内存模型的基础1. 总述2. 简介二、 进一步了解Java内存模型(一)重排序(为了优化、提升性能)(二)顺序一致性内存模型三、 关键词的内存语义(一)volatile(二) 锁写在最后 说明:本文的大部分内容参考和摘取了《Java并发编程艺术》这本书,对我来说也相当于做笔记吧。 一、 Java内存模型的基础 1. 总述 内存模型,我简单的理解就是Java在运行过程中的JVM对内存进行一系列操作的框架或者了流程(仅代表个人观点)。 在并发编程中,主要需要处理两个关键的问题:线程之间的通

教我数理化的博客 315

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

JAVA基础驿站,Java基础:内存模型

在java基础当中,有很重要一块的内容,就是关于java当中的内存模型,所涉及的问题无非就是关于java当中的类、实例、变量、常量、静态变量、方法等blabla的东西都分别存储在什么地方。这部分的内容虽然繁琐,但是也是面试当中经常涉及询问的部分,今天就在这里总结一下java当中的内存模型。首先我们来看一下java的内存模型大体分为了几个部分:从图片当中可以看到,java运行是的内存模型,大体分为了...

weixin_34457571的博客 77

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Java内存模型详解:理解并发编程基础

安全发布是避免数据竞争的关键。常见的安全发布方式有四种:通过。

qq_35974860的博客 11

基础篇:JAVA的内存模型

介绍 了解JAVA多线程的数据安全之前,我们需要先了解JAVA的内存模型,每个线程有一块自己的工作内存区,另外一块主内存,他们的作用如下: 主内存:存放各个线程共享的数据 工作内存:存放着从主内存拷贝的变量 为了正确的存取变量,它们的步骤如下: 第一步:线程先清空自己的工作内存; 第二步:锁定主内存,并读取数据; 第三步:执行代码并且可能修改工作内存中的数据; 第四步:将工作内存中的数据写入并解锁主内存 数据操作 线程的操作(6个) 通过上面的步骤,我们可以了解到线程可以有以下6种操作,这些操作都是原子

yuanyuneixin1的专栏 170

并发基础:Java内存模型

一.现代计算机的并发问题 1.现代的多CPU计算机已经普及,也就意味着有多Cache,并发时也就意味着存在着一定的风险: 现在我们要让计算机计算1+1-1的操作,计算机进行多核并发运算: 假如两个CPU同时从主存中读到同一个数据1存到各自的缓存中,CPU1将其加1结果2存到主存中,另一个CPU2将其减一结果0存到主存中,如果是CPU1的存入执行先于2,那么最后结果为0,反之结果为2,它们都不是正确的结果,我们要的正确结果为1 2.对于CPU多缓存的并发数据安全问题,诞生了MESI协议,该协议用于保证多个C

c1776167012的博客 208

Java核心基础九:JVM内存模型

JVM内存模型定义、结构图、各部分定义和功能,常见问题与调优

Xyuan的博客 728

基础:Java内存模型(JMM)

Java内存模型,有序性、原子性,可见性

weixin_42277946的博客 514

并发理论基础:Java 内存模型JMM

在并发理论基础:缓存可见性、MESI、内存屏障一文中分析了缓存可见性导致的并发问题。为了解决缓存可见性问题所以有了缓存一致性协议MESI,但是MESI的同步等待机制会影响性能,所以用了 storeBuffer 来优化,但是优化过后还是会在一些场景存在可见性问题。这个时候又不能单方面的放弃优化,所以就提供一套内存屏障些指令来让我们的开发人员可以根据自己的场景来决定什么是需要禁用CPU缓存优化来避免可见性问题。 在并发理论基础:指令重排序问题一文中分析了指令重排序现象引发的并发问题。虽然 CP...

weixin_68320784的博客 662

Java基础必备:内存模型和线程特性

本文概述:主要是以Java内存模型和线程特性两方面开展,图解加源码形式构成; 课程链接:突破JAVA万人面试,懂多线程者得天下 一、Java内存模型 Java内存模型是每个java程序员必须掌握理解的,这是Java的核心基础,对我们编写代码特别是并发编程时有很大帮助。由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分。 1.1Java程序执行流程回顾 如图所示 首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.

weixin_44233268的博客 142
上一篇: Java跨平台原理分析
下一篇: Java内存模型和硬件内存模型的联系是什么?
程序媛_小白
博客等级 码龄5年 322粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值