【Java基础总结】-了解Java线程调度、并发安全及锁优化

Java中的锁优化 锁优化是提高程序并发性能的关键手段,包括使用合适的锁类型如读写锁、可重入锁以适应不同场景;减小锁粒度,将锁作用范围限制在小范围代码或数据上以减少锁竞争;锁分离,将不同功能或数据用不同锁管理以避免不必要竞争;锁粗化,合并细小锁减少请求释放次数但需注意锁竞争;使用乐观锁,基于版本号控制并发,适合写少读多场景;以及使用无锁算法,通过原子操作、CAS等保证数据正确性,适合高并发低延迟场景。 阅读详情

Java内存模型

Java虚拟机提供的同步机制

  • synchronized关键字
  • java.util.concurrent包
  • volatile关键字 (最轻量级的同步机制)

对于volatile型变量的特殊规则

当一个变量定义为volatile之后,它将具备两种特性:第一是保证此变量对所有线程的可见性,这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。第二个语义是禁止指令重排序优化,普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。

ps 指令重排序:为了使处理器内部的运算单元能尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果一致,但并不保证程序中各个语句计算的先后顺序与输入代码中的顺序一致,因此,如果存在一个计算任务依赖另外一个计算任务的中间结果,那么其顺序性并不能靠代码的先后顺序来保证。

由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁(使用synchronized或java.util.concurrent中的原子类)来保证原子性。

  • 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。
  • 变量不需要与其他的状态变量共同参与不变约束

Java线程并发过程如何处理原子性、可见性和有序性这三个特征

  • 原子性:由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和write,我们大致认为基本数据类型的访问读写是具备原子性的。synchronized关键字和java.util.concurrent包能保证原子性。
  • 可见性:可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从内存刷新变量这种依赖主内存作为传递媒介的方式来实现可见性的。无论是普通变量还是volatile变量都是如此,普通变量与volatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存以及每次使用前立即从主内存刷新。除了volatile之外,Java还有两个关键字能实现可见性,即synchronized和final。
  • 有序性:如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的。前半句是指“线程内变现为串行的语义”,后半句是指“指令重排序”现象和“工作内存与主内存同步延迟”现象。
    Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile关键字本身就包含了禁止指令重排序的语义,而synchronized则是由“一个变量在同一个时刻只允许一条线程对其进行lock操作”这条规则获得的,这条规则决定了持有同一个锁的两个同步块只能串行地进行。

Java与线程

线程的实现

  • 使用内核线程实现
    每个内核线程可以视为内核的一个分身,这样操作系统就有能力同时处理多件事情,支持多线程的内核就叫做多线程内核。
    内核线程实现的优缺点:由于内核线程的支持,每个轻量级进程都成为一个独立的调度单元,即使有一个轻量级进程在系统调用中阻塞 ,也不会影响整个进程继续工作。它的局限性在于:系统调用的代价相对较高,需要在用户态和内核态之间来回切换;其次每个轻量级进程都需要有一个内核线程支持,要消耗一定的内核资源,因此一个系统支持轻量级进程的数量是有限的。
    轻量级进程与内核线程之间1:1的关系
  • 使用用户线程实现
    用户线程的建立、同步、销毁和调度完全在用户态中完成,不需要内核的帮助。如果程序实现得当,这种线程不需要切换到内核态,因此操作可以是非常快速且低消耗的,也可以支持规模更大的线程数量。
    实用用户线程的优势在于不需要系统内核支援,劣势也在于没有系统内核的支援,所有的线程操作都需要用户程序自己处理。有一些复杂的问题诸如“阻塞如何处理”、“多处理系统中如何将线程映射到其他处理器上”这类问题解决起来将会异常困难,甚至不可能完成。现在使用用户线程的程序越来越少了。
    进程与用户线程之间1:N的关系
  • 使用用户线程加轻量级进程混合实现
    在这种混合模式下,既存在用户线程,也存在轻量级进程。用户线程还是完全建立在用户空间中,因此用户线程的创建、切换、析构等操作依然廉价,并且可以支持大规模的用户线程并发。而操作系统提供支持的轻量级进程则作为用户线程和内核线程之间的桥梁,这样可以使用内核提供的线程调度功能及处理器映射,并且用户线程的系统调用要通过轻量级线程来完成,大大降低了整个进程被完全阻塞的风险。
    用户线程与轻量级进程的数量比是不定的,即为N:M的关系。

线程的调度

线程调度是指系统为线程分配处理器使用权的过程。主要调度方式有两种,分别是协同式线程调度和抢占式线程调度。

1.如果使用协同式调度的多线程系统, 线程的执行时间由线程本身来控制,线程把自己的工作执行完了之后,要主动通知系统切换到另一个线程上。优点:实现简单,而且由于线程要把自己的事情干完后才会进行线程切换,切换操作对线程自己是可知的,所以没有说明线程同步的问题。劣势:线程的执行时间是不可控的,甚至如果一个线程编写有问题,一直不告诉系统进行线程切换,那么程序就会一直阻塞在那儿,导致系统相当不稳定。

2.如果使用抢占式调度的多线程系统,那么每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定。在这种实现线程调度的方式下,线程的执行时间是系统可控的,也不会 有一个线程导致整个进程阻塞的问题,Java使用的线程调度方式就是抢占式调度。

状态转换

Java语言定义了5种线程状态,在任意一个时间点,一个线程只有且只有其中一种状态:

  • 新建(New):创建后还未启动的线程处于这种状态
  • 运行(Runnable):Runnable包括操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间。
  • 无限期等待(Waiting):处于这种状态的线程不会被分配CPU执行时间,它们要等待被其他线程显示地唤醒。以下方法会让线程陷入无限期的等待状态
    • 没有设置Timeout参数的Object.wait()方法。
    • 没有设置Timeout参数的Thread.join()方法。
    • LockSupport.park()方法。
  • 期限等待(Timed Waiting):处于这种状体的线程也不会被分配CPU执行时间,不过无需等待被其他线程显示地唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待状态:
    • Thread.sleep()方法
    • 设置了Timeout参数的Object.wait()方法。
    • 设置了Timeout参数的Thread.join()方法。
    • LockSupport.parkNanos()方法。
    • LockSupport.parkUntil()方法。
  • 阻塞(Blocked):线程被阻塞了,”阻塞状态”与”等待状态”的区别是:”阻塞状态”在等待着获取到一个排他锁,这个事件将在另外一个线程放弃这个锁的时候方式;而”等待状态”则是在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
  • 结束(Terminated):已终止线程的线程状态,线程已经结束执行。

线程安全的实现方法

1.互斥同步
同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一个线程使用。(互斥是方法,同步是目的)
互斥实现方式:临界区、互斥量、信号量
在Java中,互斥同步手段有:
①synchronized关键字
②使用java.util.concurrent包中的重入锁(ReentrantLock)

2.非阻塞同步
先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生了冲突,那就再采取其他的补偿措施(最常见的补偿措施就是不断地重试,知道成功为止)

3.无同步方案
同步只是保证共享数据争用时的正确性的手段,如果一个方法本来就不涉及共享数据,那它自然就无须任何同步措施去保证正确性。
①可重入代码:执行的任意时刻中断,再调用不会出现任何错误。
②线程本地存储:把共享数据的可见范围限制在同一个线程之内,这样,无需同步也能保证线程之间不出现数据争用的问题。

锁优化

以下这些技术都是为了在线程之间更高效地共享数据,以及解决竞争问题,从而提高程序的执行效率。

  • 自旋锁和自适应自旋
    在许多应用上,共享数据的锁定状态只会持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。如果物理机有一个以上的处理器,能让两个或以上的线程同时并行执行,我们就可以让后面请求锁的哪个线程”稍等一下“,但不放弃处理器的执行时间,看看持有锁的线程是否很快就会释放锁。为了让线程等待,我们只需要让线程执行一个忙循环(自旋),这项技术就是所谓的自旋锁。

    在JDK1.6中引入了自适应的自旋锁。自适应意味着自旋的时间不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。

  • 锁消除
    锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在数据共享竞争的锁 进行消除。

  • 锁粗化
    原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小—只在共享数据的实际作用域中才进行同步,这样是为了是的需要同步的操作数量尽可能变小,如果存在锁竞争,那等待锁的线程也能尽可能拿到锁。

  • 轻量级锁
    轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。
    轻量级锁能提升程序同步性能的依据是”对于绝大部分的锁,在整个同步周期内都是不存在竞争的“,这是一个经验数据。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销外,还额外使用CAS操作,因此在有竞争的情况下,轻量级锁会比传统的重量级锁更慢。

  • 偏向锁
    偏向锁也是JDK1.6中引入的一项锁优化,它的目的是消除数据在无竞争情况下的同步原语,进一步提高程序的运行性能。偏向锁会偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再进行同步。
    偏向锁可以提高带有同步但无竞争的程序性能。它同样是一个带有效益权衡性质的优化,也就是说,它并不一定总是对程序运行有利,如果程序中大多数的锁总是被多个不同的线程访问,那偏向模式就是多余的。

【Java面试并发多线程】Synchronized锁的讲解 在我们和面试官吹多线程的时候,我们务必会涉及到锁的问题,这就需要我们死磕并发并深入剖析synchronized底层原理了,希望可以帮到你,哈哈~~ 1.面试经验: 面试官问你,你有没有接触过多线程的问题 复习的不错的朋友可以说:有接触到,在项目中因为一些业务,哪哪有使过多线程,怎么使用的,然后再去深入讲解多线程知识。 如果你之前只是粗略的学习过多线程,面试初级开发的话,你可以这样回答:因为项目的限制,很少使用多线程,但是多线程怎么使用还是会的,也做过一些窗口卖票的多线程小案例。 2.线程的并发问题: 在 阅读详情

相关推荐

Python 静态导入与动态导入

python中模块的静态导入 与 动态导入(运行时指定模块),以及具体对应示例。

慢也好,步子小也好,往前走就好~ 717

《Java并发编程的艺术》笔记

《Java并发编程的艺术》笔记 第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换。 减少上下文切换的方法有4种:无锁并发编程、CAS算法、使用最少线程、使用协程。 无锁并发编程:不同线程处理不同分片的数据,如数据哈希取模分片等。 CAS算法:java的A...

weixin_30535843的博客 371

【Java】JAVA知识总结浅析

Java是一门功能强大的编程语言,广泛应用于多个领域。Java的编程思想,包括面向过程和面向对象编程,Java的发展历史,各版本的特点,JVM原理,数据类型,Java SE与Java EE的区别,应用场景,JDK与JDBC,Java Web技术,Spring Boot系列,以及MyBatis框架的基本实现,最后还将讨论Java在大数据、人工智能、嵌入式和Android等领域的应用。

wnm23的专栏 5251

Java多线程中提到的原子性和可见性、有序性

原子性 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。如果一个操作时原子性的,那么多线程并发的情况下,就不会出现变量被修改的情况比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安

jaryle的专栏 1万+

AGV路径规划实战:如何用Python+ROS实现激光SLAM导航(附避障代码)

本文提供了一份基于Python和ROS实现AGV激光SLAM导航的实战指南。内容涵盖从Docker环境搭建、激光雷达数据处理、Gmapping建图,到Move_Base全局/局部路径规划与TEB局部规划器配置的全流程。重点解析了如何通过参数调优实现稳定导航,并附带了紧急避障代码,帮助开发者快速构建具备自主路径规划与实时避障能力的AGV系统。

pepsi的博客 1236

普通人也能看懂的Transformer源代码解释(PyTorch)

Transformer源代码解释之PyTorch篇 章节 词嵌入 位置编码 多头注意力 搭建Transformer 在这里插入图片描述 词嵌入 Transformer本质上是一种Encoder,以翻译任务为例,原始数据集是以两种语言组成一行的,在应用时,应是Encoder输入源语言序列,Decoder里面输入需要被转换的语言序列(训练时)。一个文本常有许多序列组成,常见操作为将序列进行一些预处理(如词切分等)变成列表,一个序列的列表的元素通常为词表中不可切分的最小词,整个文本就是一个大列表,元素为一个一

qq_50974223的博客 4170

线程(二)

创建线程有几种方式?哪种受欢迎 为什么? 有三种方式可以创建线程:继承Thread类、实现Runnable接口、应用程序可以使用Executor框架来创建线程池 实现Runnable接口这种方式更受欢迎,因为这个不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承,但Java不支持多继承,所以只能实现接口。同时线程池也是非常高效的,很容易实现和使用 Java多线程回调是什么意思? 所谓回调,就是客户程序C调用服务程序S中的某个方法A,然后S又在某个时候反过来调用C中的某个方法B,对

weixin_44387195的博客 764

GMSL2摄像头接入避坑指南:从FMC子卡配置到V4L2调用的完整流程(附Ubuntu20.04实测)

本文详细解析了GMSL2摄像头接入的全流程,从FMC子卡配置到V4L2调用的完整指南。基于XC7Z100平台实测经验,提供了硬件选型、带宽优化、Linux驱动配置及高分辨率采集的实战技巧,帮助开发者规避常见问题,提升系统稳定性与性能。

weixin_33737774的博客 419

由JVM深入了解Java的线程安全与锁优化

目录 •写在前面 •线程安全 Java语言中的线程安全 线程安全的实现方法 •锁优化 自旋锁与自适应自旋 锁消除 锁粗化 轻量级锁 偏向锁 •写在前面 讲道理,在谈及线程安全以及锁优化之前,需要先搞清楚啥是线程,像那些硬概念这里我就不多说,什么线程是比进程更轻量级的调度执行单位,线程的引入,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源,又可以独立调度(...

BoCong-Deng的博客 1万+

ROS机器人里程计模型

3.5 移动机器人系统模型 相信大家的机器人平台STM32端底层控制和机器人urdf建模都已经顺利完成了,在正式开始ros端编写机器人启动功能包之前,我们还不得不学习一些必要的理论知识。别担心数学不好,这里基本都是高中数学。下面我们开始,Are you ready? 没准备好也开始了。 3.5.1 常用坐标系系统模型 在移动机器人技术研究中,最为常用的坐标系统是笛卡尔坐标系统。而在SLAM算法研究中,有如下几个比较常见的笛卡尔坐标系统,它们分别为机器人坐标系XR YR OR 、传感器坐标系XS YS OS

「小白学移动机器人」一个专注分享移动机器人相关知识的公众号! 1万+

RNA-seq分析:Step8(富集分析)

RNA-seq富集分析是一种用于分析基因表达数据中特定基因或通路是否富集的分析方法。其基本思想是比较不同基因对应的转录本/基因之间的表达差异及其对应的基因注释信息,通过统计学方法评估差异的显著性,从而确定是否存在某些特定的功能通路或基因集合富集的情况。常用的RNA-seq富集分析工具包括GOseq、KEGG(KEGG enrichment analysis)、DAVID(Database for Annotation, Visualization and Integrated Discovery)等。这

沉香best的博客 3634

【Java高效并发系列】- 线程安全与锁优化

本章关注虚拟机如何实现“高效”,以及虚拟机对并发代码提供了什么样的优化手段高效并发,首先需要保证并发的正确性,然后在此基础上实现高效。

m0_68383079的博客 883

Ubuntu上通过FinalShell或Asbru访问CentOS虚拟机

使用FinalShell或Asbru远程连接虚拟机

howard2005的专栏 2280

第13章 线程安全与锁优化

在一项工作进行期间,对象会被不停地中断和切换,对象的属性(数据)可能会在中断期间被修改和变脏,在计算机中这是再正常不过的事。所以我们必须让程序在计算机中正确无误地运行,然后再考虑如何将代码组织得更好,让程序运行得更快。要保证程序正确运行,首先需要确保并发的正确性。

weixin_45740473的博客 3415

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

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

WINCC7.3破解文件

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

java并发编程:管程、内存模型、无锁并发、线程池、AQS原理与锁、线程安全集合类、并发设计模式

java并发编程:管程、内存模型、无锁并发、线程池、AQS原理与锁、线程安全集合类、并发设计模式

Henrik-Yao的博客 1571

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java并发:线程安全与锁优化

概述人们很难想象现实中的对象在一项工作进行期间,会被不停地中断和切换,对象的属性(数据)可能会在中断期间被修改和变“脏”,而这些事情在计算机世界中则是很正常的事情。有时候,良好的设计原则不得不向现实做出一些让步,我们必须让程序在计算机中正确无误地运行,然后再考虑如何将代码组织得更好,让程序运行更快。对于“高效并发”来说,首先需要保证并发的正确性,然后在此基础上实现高效。1.线程安全《Java Co...

程序员囧辉 4799

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Java 多线程优化:锁优化与线程安全的设计模式

高效的多线程编程不仅能提升系统的性能,还能确保程序在复杂的并发环境中运行稳定。通过合理的锁优化、线程安全设计模式以及使用并发工具包,可以极大地提升并发编程的效率和可维护性。

一名热衷于技术的全栈开发者,专注于前端与后端的全面技术探索。在这里,我将分享我在技术领域的学习与成长,助力更多开发者的进步。 900

Java多线程与并发编程全面解析-高效任务调度与优化策略

多线程是指在单个程序中同时运行多个线程,每个线程都可以独立完成特定的任务。Java通过Thread类和Runnable接口提供了多线程的基本实现。Java中的多线程和并发编程是现代应用开发中非常重要的一部分,它们能够显著提升系统的响应能力和处理能力。然而,要实现高效的并发编程并非易事,需要开发者在任务调度、资源管理和并发控制方面进行深入设计。任务调度策略:通过优先级调度、固定时间间隔调度和延迟调度等策略,开发者可以更灵活地控制多线程任务的执行,确保重要任务的及时处理,并提高系统的吞吐量和响应速度。

一键难忘的博客 3121

Java 线程安全与锁优化

什么是线程安全? 线程安全经常会被各种行业大佬或者面试官大佬挂在嘴边,如何找到一个通俗易懂一点的方式解释线程安全呢,伟大的砖家给出了答案:如果一个对象可以安全的被多个对象使用,那它就是线程安全的。是的,这种回答非常的巧妙精彩…巧妙到你无法怼它是错误的…但是也无法从中找到任何有用信息… 众多定义中,《Java Concurrency In Practice》的作者Brian Goetz对线程安全...

一只猿的自我修养 3530

JAVA高并发——锁的优化

减少锁的持有时间、减小锁粒度、用读写锁来替代独占锁、锁分离、锁粗化

码说芯语的博客 1183

Java基础——Java并发详解(线程、终端、互斥同步、线程协作、线程状态、AQS、Java内存模型、线程安全、锁优化等)

GFM-TOC。

qq_44182424的博客 1034

java线程安全和锁优化

面向对象的编程思想是站在现实世界的角度去抽象和解决问题,他把数据和行为都看作是对象的一部分,这样可以让程序员能以符合现实世界的思维方式来编写和组织程序。 线程安全的一个恰当的定义:当多个线程访问一个对象时,如果不用考虑这些线程在运行环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的 。 按照线程安全

xulu_258的专栏 3260

JAVA线程安全与锁优化

文章目录1.概述2.线程2.1.线程的实现方式2.2.java中线程的实现方式3.线程安全3.1.线程安全的强度3.2.线程安全的实现方式4.锁优化4.1.自旋锁与自适应自旋4.2.锁消除4.3.锁粗化4.4.轻量级锁4.5.偏向锁 1.概述 2.线程 2.1.线程的实现方式 2.2.java中线程的实现方式 3.线程安全 3.1.线程安全的强度 3.2.线程安全的实现方式 4.锁优化 4.1.自...

凶猛的小蜜蜂 380

Java 并发编程高级实战:从线程安全到锁优化的深度解析

在理解 Java 并发高级特性之前,我们首先要明确:传统并发编程在高并发场景(如秒杀系统、分布式任务调度)中存在明显短板,这些痛点会导致线程安全问题、性能低下或资源浪费。

m0_72256543的博客 862

一夜搞懂 | JVM 线程安全与锁优化

前言 本文已经收录到我的 Github 个人博客,欢迎大佬们光临寒舍: 我的 GIthub 博客 学习导图 一.为什么要学习内存模型与线程? 之前我们学习了内存模型和线程,了解了 JMM 和线程,初步探究了 JVM 怎么实现并发,而本篇文章,我们的关注点是 JVM 如何实现高效 并发编程的目的是为了让程序运行得更快,提高程序的响应速度,虽然我们希望通过多线程执行任务让程序运行得...

weixin_40505691的博客 1135

精通 Java 多线程:从基础到高并发应用的优化与设计

Java 多线程编程是高性能、可扩展应用开发的重要组成部分。从线程的创建、同步到并发优化,开发者需要掌握多种工具和技术,灵活应对高并发场景中的各种挑战。通过线程池的使用、无锁编程和合适的数据结构,能够有效提升系统的性能,避免资源竞争和死锁问题。掌握这些基础和高级概念,不仅能让你在多线程编程中游刃有余,也能为你设计和优化高并发、高可用的系统提供强大的支持。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1441
上一篇: 【Java基础总结】-异常与泛型
下一篇: 【Java基础总结】-反射机制与代理机制
gamedev˚
博客等级 码龄12年 280粉丝 293原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值