谈谈Java中让你眼花缭乱的18把锁

Windows10环境下Flink-1.18.0的快速安装与配置指南 本文提供了一份详细的Windows10环境下Apache Flink-1.18.0单机版安装与配置指南。内容涵盖Java环境准备、软件下载解压、环境变量配置、集群启动、示例程序运行验证以及常见问题排查,旨在帮助开发者快速在本地搭建Flink流处理学习与测试环境。 阅读详情
  • 乐观锁和悲观锁

  • 独占锁和共享锁

  • 互斥锁和读写锁

  • 公平锁和非公平锁

  • 可重入锁

  • 自旋锁

  • 分段锁

  • 锁升级(无锁|偏向锁|轻量级锁|重量级锁)

  • 锁优化技术(锁粗化、锁消除)

乐观锁和悲观锁

悲观锁

悲观锁 对应于生活中悲观的人,悲观的人总是想着事情往坏的方向发展。

举个生活中的例子,假设厕所只有一个坑位了,悲观锁上厕所会第一时间把门反锁上,这样其他人上厕所只能在门外等候,这种状态就是「阻塞」了。

回到代码世界中,一个共享数据加了悲观锁,那线程每次想操作这个数据前都会假设其他线程也可能会操作这个数据,所以每次操作前都会上锁,这样其他线程想操作这个数据拿不到锁只能阻塞了。

在 Java 语言中 synchronized 和 ReentrantLock 等就是典型的悲观锁,还有一些使用了 synchronized 关键字的容器类如 HashTable 等也是悲观锁的应用。

乐观锁

乐观锁 对应于生活中乐观的人,乐观的人总是想着事情往好的方向发展。

举个生活中的例子,假设厕所只有一个坑位了,乐观锁认为:这荒郊野外的,又没有什么人,不会有人抢我坑位的,每次关门上锁多浪费时间,还是不加锁好了。你看乐观锁就是天生乐观!

回到代码世界中,乐观锁操作数据时不会上锁,在更新的时候会判断一下在此期间是否有其他线程去更新这个数据。

乐观锁可以使用 版本号机制 和 CAS算法 实现。在 Java 语言中 java.util.concurrent.atomic 包下的原子类就是使用CAS 乐观锁实现的。

两种锁的使用场景

悲观锁和乐观锁没有孰优孰劣,有其各自适应的场景。

乐观锁适用于写比较少(冲突比较小)的场景,因为不用上锁、释放锁,省去了锁的开销,从而提升了吞吐量。

如果是写多读少的场景,即冲突比较严重,线程间竞争激励,使用乐观锁就是导致线程不断进行重试,这样可能还降低了性能,这种场景下使用悲观锁就比较合适。

独占锁和共享锁

独占锁

独占锁 是指锁一次只能被一个线程所持有。如果一个线程对数据加上排他锁后,那么其他线程不能再对该数据加任何类型的锁。获得独占锁的线程即能读数据又能修改数据。

JDK中的 synchronized 和 java.util.concurrent(JUC) 包中Lock的实现类就是独占锁。

共享锁

共享锁 是指锁可被多个线程所持有。如果一个线程对数据加上共享锁后,那么其他线程只能对数据再加共享锁,不能加独占锁。获得共享锁的线程只能读数据,不能修改数据。

在 JDK 中 ReentrantReadWriteLock 就是一种共享锁。

互斥锁和读写锁

互斥锁

互斥锁 是独占锁的一种常规实现,是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。

互斥锁一次只能一个线程拥有互斥锁,其他线程只有等待。

读写锁

读写锁 是共享锁的一种具体实现。读写锁管理一组锁,一个是只读的锁,一个是写锁。

读锁可以在没有写锁的时候被多个线程同时持有,而写锁是独占的。写锁的优先级要高于读锁,一个获得了读锁的线程必须能看到前一个释放的写锁所更新的内容。

读写锁相比于互斥锁并发程度更高,每次只有一个写线程,但是同时可以有多个线程并发读。

在 JDK 中定义了一个读写锁的接口: ReadWriteLock

public interface ReadWriteLock {
    /**
     * 获取读锁
     */
    Lock readLock();

    /**
     * 获取写锁
     */
    Lock writeLock();
}

ReentrantReadWriteLock 实现了 ReadWriteLock 接口,具体实现这里不展开,后续会深入源码解析。

公平锁和非公平锁

公平锁

公平锁 是指多个线程按照申请锁的顺序来获取锁,这里类似排队买票,先来的人先买,后来的人在队尾排着,这是公平的。

在 java 中可以通过构造函数初始化公平锁

/**
* 创建一个可重入锁,true 表示公平锁,false 表示非公平锁。默认非公平锁
*/
Lock lock = new ReentrantLock(true);

非公平锁

非公平锁 是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转,或者饥饿的状态(某个线程一直得不到锁)。

在 java 中 synchronized 关键字是非公平锁,ReentrantLock默认也是非公平锁。

/**
* 创建一个可重入锁,true 表示公平锁,false 表示非公平锁。默认非公平锁
*/
Lock lock = new ReentrantLock(false);

可重入锁

可重入锁 又称之为 递归锁 ,是指同一个线程在外层方法获取了锁,在进入内层方法会自动获取锁。

对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁。对于Synchronized而言,也是一个可重入锁。

敲黑板:可重入锁的一个好处是可一定程度避免死锁。

以 synchronized 为例,看一下下面的代码:

public synchronized void mehtodA() throws Exception{
 // Do some magic tings
 mehtodB();
}

public synchronized void mehtodB() throws Exception{
 // Do some magic tings
}

上面的代码中 methodA 调用 methodB,如果一个线程调用methodA 已经获取了锁再去调用 methodB 就不需要再次获取锁了,这就是可重入锁的特性。如果不是可重入锁的话,mehtodB 可能不会被当前线程执行,可能造成死锁。

自旋锁

自旋锁 是指线程在没有获得锁时不是被直接挂起,而是执行一个忙循环,这个忙循环就是所谓的自旋。

自旋锁的目的是为了减少线程被挂起的几率,因为线程的挂起和唤醒也都是耗资源的操作。

如果锁被另一个线程占用的时间比较长,即使自旋了之后当前线程还是会被挂起,忙循环就会变成浪费系统资源的操作,反而降低了整体性能。因此自旋锁是不适应锁占用时间长的并发情况的。

在 Java 中, AtomicInteger 类有自旋的操作,我们看一下代码:

public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

CAS 操作如果失败就会一直循环获取当前 value 值然后重试。

另外自适应自旋锁也需要了解一下。

在JDK1.6又引入了自适应自旋,这个就比较智能了,自旋时间不再固定,由前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定。如果虚拟机认为这次自旋也很有可能再次成功那就会次序较多的时间,如果自旋很少成功,那以后可能就直接省略掉自旋过程,避免浪费处理器资源。

分段锁

分段锁 是一种锁的设计,并不是具体的一种锁。

分段锁设计目的是将锁的粒度进一步细化,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。

在 Java 语言中 CurrentHashMap 底层就用了分段锁,使用Segment,就可以进行并发使用了。

锁升级(无锁|偏向锁|轻量级锁|重量级锁)

JDK1.6 为了提升性能减少获得锁和释放锁所带来的消耗,引入了4种锁的状态: 无锁 、 偏向锁 、 轻量级锁 和 重量级锁 ,它会随着多线程的竞争情况逐渐升级,但不能降级。

无锁

无锁 状态其实就是上面讲的乐观锁,这里不再赘述。

偏向锁

Java偏向锁(Biased Locking)是指它会偏向于第一个访问锁的线程,如果在运行过程中,只有一个线程访问加锁的资源,不存在多线程竞争的情况,那么线程是不需要重复获取锁的,这种情况下,就会给线程加一个偏向锁。

偏向锁的实现是通过控制对象 Mark Word 的标志位来实现的,如果当前是 可偏向状态 ,需要进一步判断对象头存储的线程 ID 是否与当前线程 ID 一致,如果一致直接进入。

轻量级锁

当线程竞争变得比较激烈时,偏向锁就会升级为 轻量级锁 ,轻量级锁认为虽然竞争是存在的,但是理想情况下竞争的程度很低,通过 自旋方式 等待上一个线程释放锁。

重量级锁

如果线程并发进一步加剧,线程的自旋超过了一定次数,或者一个线程持有锁,一个线程在自旋,又来了第三个线程访问时(反正就是竞争继续加大了),轻量级锁就会膨胀为 重量级锁 ,重量级锁会使除了此时拥有锁的线程以外的线程都阻塞。

升级到重量级锁其实就是互斥锁了,一个线程拿到锁,其余线程都会处于阻塞等待状态。

在 Java 中,synchronized 关键字内部实现原理就是锁升级的过程:无锁 --> 偏向锁 --> 轻量级锁 --> 重量级锁。这一过程在后续讲解 synchronized 关键字的原理时会详细介绍。

锁优化技术(锁粗化、锁消除)

锁粗化

锁粗化 就是将多个同步块的数量减少,并将单个同步块的作用范围扩大,本质上就是将多次上锁、解锁的请求合并为一次同步请求。

举个例子,一个循环体中有一个代码同步块,每次循环都会执行加锁解锁操作。

private static final Object LOCK = new Object();

for(int i = 0;i < 100; i++) {
    synchronized(LOCK){
        // do some magic things
    }
}

经过 锁粗化 后就变成下面这个样子了:

 synchronized(LOCK){
     for(int i = 0;i < 100; i++) {
        // do some magic things
    }
}

锁消除

锁消除 是指虚拟机编译器在运行时检测到了共享数据没有竞争的锁,从而将这些锁进行消除。

举个例子让大家更好理解。

public String test(String s1, String s2){
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer.append(s1);
    stringBuffer.append(s2);
    return stringBuffer.toString();
}

上面代码中有一个 test 方法,主要作用是将字符串 s1 和字符串 s2 串联起来。

test 方法中三个变量s1, s2, stringBuffer, 它们都是局部变量,局部变量是在栈上的,栈是线程私有的,所以就算有多个线程访问 test 方法也是线程安全的。

我们都知道 StringBuffer 是线程安全的类,append 方法是同步方法,但是 test 方法本来就是线程安全的,为了提升效率,虚拟机帮我们消除了这些同步锁,这个过程就被称为 锁消除 。

StringBuffer.class

// append 是同步方法
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

一张图总结:

前面讲了 Java 语言中各种各种的锁,最后再通过六个问题统一总结一下:

原文链接:https://www.tuicool.com/articles/vA3yIjU

Hadoop单机模式入门:Ubuntu 18.04 + Java 8 零基础实战 Hadoop单机模式是理解分布式计算框架本质的基石,它剥离了集群复杂性,聚焦于MapReduce工作流程、HDFS抽象模型与YARN资源调度的核心原理。作为最轻量级运行态,它以本地文件系统模拟HDFS、单JVM内执行MapReduce任务,实现可调试、可断点、可日志追踪的确定性计算。其技术价值在于降低学习门槛、强化概念认知、加速故障定位,并为伪分布式及生产集群部署提供可靠验证基线。典型应用场景包括WordCount验证、电信数据清洗、招聘薪资分位统计等MapReduce综合应用案例。本文基于Ubuntu 1 阅读详情

相关推荐

Java并发锁机制全解析:从synchronized到StampedLock的实战指南

在并发编程中,锁是保证线程安全的核心机制,用于解决多线程环境下的原子性、可见性和有序性问题。其原理是通过同步机制控制对共享资源的访问,确保数据一致性。锁的技术价值在于提升程序执行效率与稳定性,避免竞态条件导致的数据错误。应用场景涵盖数据库连接池、缓存系统、高并发服务等需要协调多线程访问的领域。本文聚焦Java并发包中的锁工具,深入剖析synchronized、ReentrantLock等锁机制,并结合StampedLock的乐观读特性,探讨如何根据实际场景选择合适的锁策略,优化系统性能。

weixin_26874745的博客 507

java锁详解

java当中的锁、是在多线程环境下为保证共享资源健康、线程安全的一种手段。 线程操作某个共享资源之前,先对资源加一层锁,保证操作期间没有其他线程访问资源,当操作完成后,再释放锁。

SRY12240419的博客 1万+

Ubuntu 18.04 安装 Node.js 实战指南:NodeSource 与 nvm 双轨方案

Node.js 是基于 V8 引擎的 JavaScript 运行时环境,使 JS 能脱离浏览器执行系统级任务;其核心依赖 libuv 抽象 I/O 操作,版本兼容性直接影响 npm、node-gyp 等工具链稳定性。在已结束官方支持的 Ubuntu 18.04 上,系统 APT 源仅提供过时的 Node.js 8.10.0 和不配套的 npm 3.5.2,导致 async/await 缺失、Python 版本冲突及编译失败等典型问题。本文聚焦 LTS 兼容性与多版本管理需求,详解 NodeSource 提供

weixin_34205826的博客 450

Java锁

Java锁是什么?为什么要用Java锁? 在并发编程中,经常遇到多个线程访问同一个共享资源 ,这时候作为开发者必须考虑如何维护数据一致性,在java中synchronized关键字被常用于维护数据一致性。synchronized机制是给共享资源上锁,只有拿到锁的线程才可以访问共享资源,这样就可以强制使得对共享资源的访问都是顺序的,因为对于共享资源属性访问是必要也是必须的。 一般在java中所说的锁...

夏目川城的博客 1425

解锁笔记智能对话:手把手配置 Obsidian Copilot 插件与硅基流动模型

本文详细介绍了如何为Obsidian笔记软件配置Copilot插件,并接入硅基流动AI模型,从而为个人知识库添加智能对话能力。通过手把手教程,指导用户完成插件安装、API Key获取、模型配置及索引构建,最终实现基于个人笔记内容的深度语义问答,提升知识管理效率。

corn8的博客 612

Qt跨平台CAN通信实战:Vector、PCAN与周立功设备统一接口设计

本文针对Qt开发中常见的多品牌CAN设备兼容难题,提出了一套统一的跨平台CAN通信接口设计方案。通过抽象层封装,实现了对Vector、PCAN和周立功设备的统一操作,上层业务代码无需修改即可在不同硬件间切换,有效解决了驱动API差异、环境配置复杂和维护成本高等痛点,显著提升了代码复用率和开发效率。

weixin_29161785的博客 329

Java中的锁详解

Java中的锁详解

浩浩的博客 4032

matebookego win11 arm 系统安装安卓子系统

一般的x86电脑如果安装android子系统,运行安卓子系统,由于要将android arm代码转译为x86代码,所以效率不一定高,但是如果电脑是arm架构的,通过安卓子系统运行android的程序执行效率就会 高不少,本文参考,都是在win11 home版本下的。两者跑分在cpu上差不太多了,大约是枭龙855的水平了,这个水平的子系统就有一定的实用性了,玩个一般游戏,刷个抖音都很流畅的。启动子系统后,点击左上角的设置,启用 “开发人员模式”。然后就可以再通运运行华为应用商店来进行安装其它应用了。

babytiger的专栏 1万+

JAVA各种锁的使用与原理专题(附源码讲义)

Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率。本文旨在对锁相关源码(本文中的源码来自JDK8)、使用场景进行举例,为读者介绍主流锁的知识点,以及不同的锁的适用场景。 Java中往往是按照是否含有某一特性来定义锁,我们通过特性将锁进行分组归类,再使用对比的方式进行介绍,帮助大家更快捷的理解相关知识。帮助大家剖析JAVA中各种锁的底层原理,例如Synchronized锁的膨胀与升级等,掌握企业面试中各种锁的面试题,胜任企业开发。 下面给出课程内容的总体分类目录:  

YOLO11改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

YOLOv11改进大全:卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总

魔改工程师的博客 4504

华为od 面试八股文_前端_03_含答案

华为od 面试八股文_前端_03_含答案

MISAYAONE的博客 2128

Java中15种锁介绍

lock()方法利用的CAS,当第一个线程A获取锁的时候,能够成功获取到,不会进入while循环,如果此时线程A没有释放锁,另一个线程B又来获取锁,此时由于不满足CAS,所以就会进入while循环,不断判断是否满足CAS,直到A线程调用unlock方法释放了该锁。代码也比较简单,使用原子引用来存放线程,同一线程两次调用lock()方法,如果不执行unlock()释放锁的话,第二次调用自旋的时候就会产生死锁,这个锁就不是可重入的,而实际上同一个线程不必每次都去释放锁再来获取锁,这样的调度切换是很耗资源的。

2301_78008478的博客 3022

YOLOv11改进 | 注意力篇 | YOLOv11引入CA注意力机制

摘要:最近关于移动网络设计的研究已经证明了通道注意力(例如,挤压和激励注意力)对于提升模型性能的显着有效性,但它们通常忽略了位置信息,而位置信息对于生成空间选择性注意力图很重要。到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv11改进有效涨点专栏,本专栏目前为新开的,后期我会根据各种前沿顶会进行论文复现,也会对一些老的改进机制进行补充,如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~3.2 在Extramodule里创建CA。在CA.py文件里添加给出的CA代码。

tsg6698的博客 2977

Java进化全解析,从Java 8到Java 24的革命性特性一网打尽

Java 8到Java 24,Java语言经历了翻天覆地的变化: 1. **Java 8**:函数式编程革命(Lambda、Stream) 2. **Java 9-11**:模块化与API增强 3. **Java 12-17**:语法糖改进(Switch表达式、文本块、记录类) 4. **Java 18-24**:并发编程革命(虚拟线程、结构化并发)

ly853602的博客 1112

Git下载与安装

一、Git下载 二、Git安装

欢迎订阅我的“JAVA全栈开发笔记(全)”专栏,价格优惠,仅需19.9元。 6万+

Google Earth Engine(GEE)——将sentinel - 2影像所有波段重采样到10m分辨率 (resample 和 projection的使用)

影像重投影是将一个影像从一个坐标系投影到另一个坐标系的过程。这通常涉及到将像素从一个平面坐标系变换到另一个平面坐标系。这可以用于许多应用中,例如建立数字高程模型(DEM)和地图制图。影像重投影通常需要进行数学计算,包括转换矩阵和插值算法,以确保像素值的准确性和精度。这次我们将对哨兵2好数据中20m分辨率的波段,重采样到10m分辨率中,然后同一参与计算。

此星光明博客 3106

mysql8.0.18+hibernate5.4.10 的配置入门详细教程

--------------摸索了许久,写个教程记录一下,以后忘了也好重新上手--------------- 运行环境:Windows10-64位操作系统 搭载配置:mysql8.0.18+hibernate5.4.10 MySQL官网:MySQL Windows10-32位:mysql8.0.18 Windows10-64位:mysql8.0.18 其他版本自行官网下载:MySQL ...

Confused-KeKe 2085

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

10个让人眼花缭乱的 HTML5 和 JavaScript 效果

作为下一代网页语言,html5 拥有很多让人期待已久的新特性。如今,很多 web 开发人员开始使用 html5 来制作各种丰富的 web 应用。本文向大家展示10个让人眼花缭乱的 html5 和 javascript 效果,让你体验下一代 web 技术的魅力,相信你看完这些例子后会对未来的 web 发展充满无限期待。 breathing galaxies 动态变换颜色和直径,可通过键盘或者

javazhuanzai的专栏 440

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java 并发编程实战

并发编程是现代软件开发的核心技能,其本质可归纳为三个关键问题:分工、同步和互斥。分工关注如何高效分配任务给线程;同步解决线程间的协作问题;互斥确保共享资源的安全访问。学习并发编程需要"跳出来看全景"建立知识体系,同时"钻进去看本质"理解底层理论模型。Java SDK提供的并发工具如Executor、Future、锁机制等,都是对这些核心问题的解决方案。掌握这些概念不仅能提升程序性能,更能保障多线程环境下的正确性。建议学习者通过思维导图梳理知识脉络,并结合实际场景深入理解管程、内存模型等基础理论。

刘大猫 2084

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

一文看懂android_maskable_layout的18种PorterDuff混合模式:图文效果对照大全

android_maskable_layout 是一款轻量级的 Android 开源遮罩布局库,它基于 FrameLayout 封装,让开发者可以像给照片贴贴纸一样,把任意 View 或 ViewGroup 裁剪成圆形、星形甚至不断变化的动画形状。实现这一切的核心机制,正是 Android 图形系统里的 PorterDuff 混合模式(PorterDuff 混合模式)。本文将带你一文看懂库中内置的

gitblog_01038的博客 907

做java前端需要学习哪些知识,2022最新

做前端需要会JAVA吗?高阶前端需要学习的知识远不及后端,如果你能学会并熟练地运用上面提到的框架,你就能在前端开发领域中找到自己的一方天地,而且还能获得丰厚的报酬和待遇。 4.当然,如果你有足够的时间和精力,你也可以学一门后端开发语言,比如php,java等等。我建议你去学java,你就能理解了。 Java要学习哪些主流框架,以及它们的运用首先用户发送请求--前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的 普通的Java对象,映射成.

神经网络爱好者 2877

《编写高质量代码:改善Java程序的151条建议》读书笔记

这本书可以作为平时写代码的一个参考书,这本书以我个人读的经验看来,最好是通过平时代码驱动的方式来读,这样吸收的快,也读的快。 这本书主要讲什么,我自己用了个思维导图概述: 根据这种导图可知,主要讲的就是Java语法、JDK API、程序性能、开源工具和框架、编程风格和编程思想等五个点。 我这次主要读的是关于开源世界和思想开源这两章,这两章相当于导图中提到的开源工具和框架、编程风格和编程思...

liinux-Talk is cheap,show me the code. 260

Java开发核心注解总结(一)

文章目录一、注解目录二、何为注解?三、Java、spring、spring Boot注解1、@SpringBootApplication2、@EnableAutoConfiguration3、@ComponentScan4、@Configuration5、@Controller6、@RestController7、@Service8、@Autowired9、@PathVariable10、@PostMapping11、@GetMapping12、@RequestMapping13、@RequestBody1

码上言 909

Java和go语言的2025年发展前景和就业形势

作为大四学长想对即将就业学生说的话。

欢迎来到我的博客! 3543

2025最新B站大学JAVA学习路线

不得不说B站的课程资源真的是丰富。 但是也是因为太丰富,也有点让人眼花缭乱。应该学哪些课程?按照什么顺序学?每个阶段的课程看哪个UP主的更好?尤其是最近几年AI崛起后,网上那些几年前的学习路线其实已经不适合当下的情况。

1486
上一篇: 和阿里面试官谈JVM调优,他居然把我的电话挂了
下一篇: 18张图带你看懂SpringBoot解析yml全流程
Java架构师小森
博客等级 码龄5年 23粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值