多线程之死锁就是这么简单

【遥感】遥感影像中的QA波段(质量评估波段)存储方式介绍 在遥感图像处理过程中,我们常使用的波段有可见光、红外、微波等波段。但是,在获取Landsat、Sentinel等卫星影像数据时,往往有其他波段影像存在,QA波段就是其中之一。QA波段是什么,它又有什么作用呢? 阅读详情

前言

只有光头才能变强

回顾前面:

本篇主要是讲解死锁,这是我在多线程的最后一篇了。主要将多线程的基础过一遍,以后有机会再继续深入!

死锁是在多线程中也是比较重要的知识点了!

那么接下来就开始吧,如果文章有错误的地方请大家多多包涵,不吝在评论区指正哦~

声明:本文使用JDK1.8

一、死锁讲解

在Java中使用多线程,就会有可能导致死锁问题。死锁会让程序一直卡住,不再程序往下执行。我们只能通过中止并重启的方式来让程序重新执行。

  • 这是我们非常不愿意看到的一种现象,我们要尽可能避免死锁的情况发生!

造成死锁的原因可以概括成三句话:

  • 当前线程拥有其他线程需要的资源
  • 当前线程等待其他线程已拥有的资源
  • 都不放弃自己拥有的资源

1.1锁顺序死锁

首先我们来看一下最简单的死锁(锁顺序死锁)是怎么样发生的:


public class LeftRightDeadlock {
    private final Object left = new Object();
    private final Object right = new Object();

    public void leftRight() {
        // 得到left锁
        synchronized (left) {
            // 得到right锁
            synchronized (right) {
                doSomething();
            }
        }
    }

    public void rightLeft() {
        // 得到right锁
        synchronized (right) {
            // 得到left锁
            synchronized (left) {
                doSomethingElse();
            }
        }
    }
}

我们的线程是交错执行的,那么就很有可能出现以下的情况:

  • 线程A调用leftRight()方法,得到left锁
  • 同时线程B调用rightLeft()方法,得到right锁
  • 线程A和线程B都继续执行,此时线程A需要right锁才能继续往下执行。此时线程B需要left锁才能继续往下执行。
  • 但是:线程A的left锁并没有释放,线程B的right锁也没有释放。
  • 所以他们都只能等待,而这种等待是无期限的–>永久等待–>死锁

1.2动态锁顺序死锁

我们看一下下面的例子,你认为会发生死锁吗?


    // 转账
    public static void transferMoney(Account fromAccount,
                                     Account toAccount,
                                     DollarAmount amount)
            throws InsufficientFundsException {

        // 锁定汇账账户
        synchronized (fromAccount) {
            // 锁定来账账户
            synchronized (toAccount) {

                // 判余额是否大于0
                if (fromAccount.getBalance().compareTo(amount) < 0) {
                    throw new InsufficientFundsException();
                } else {

                    // 汇账账户减钱
                    fromAccount.debit(amount);

                    // 来账账户增钱
                    toAccount.credit(amount);
                }
            }
        }
    }

上面的代码看起来是没有问题的:锁定两个账户来判断余额是否充足才进行转账!

但是,同样有可能会发生死锁:

  • 如果两个线程同时调用transferMoney()
  • 线程A从X账户向Y账户转账
  • 线程B从账户Y向账户X转账
  • 那么就会发生死锁。

A:transferMoney(myAccount,yourAccount,10);


B:transferMoney(yourAccount,myAccount,20);

1.3协作对象之间发生死锁

我们来看一下下面的例子:


public class CooperatingDeadlock {
    // Warning: deadlock-prone!
    class Taxi {
        @GuardedBy("this") private Point location, destination;
        private final Dispatcher dispatcher;

        public Taxi(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }

        public synchronized Point getLocation() {
            return location;
        }

        // setLocation 需要Taxi内置锁
        public synchronized void setLocation(Point location) {
            this.location = location;
            if (location.equals(destination))
                // 调用notifyAvailable()需要Dispatcher内置锁
                dispatcher.notifyAvailable(this);
        }

        public synchronized Point getDestination() {
            return destination;
        }

        public synchronized void setDestination(Point destination) {
            this.destination = destination;
        }
    }

    class Dispatcher {
        @GuardedBy("this") private final Set<Taxi> taxis;
        @GuardedBy("this") private final Set<Taxi> availableTaxis;

        public Dispatcher() {
            taxis = new HashSet<Taxi>();
            availableTaxis = new HashSet<Taxi>();
        }

        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }

        // 调用getImage()需要Dispatcher内置锁
        public synchronized Image getImage() {
            Image image = new Image();
            for (Taxi t : taxis)
                // 调用getLocation()需要Taxi内置锁
                image.drawMarker(t.getLocation());
            return image;
        }
    }

    class Image {
        public void drawMarker(Point p) {
        }
    }
}

上面的getImage()和setLocation(Point location)都需要获取两个锁的

  • 并且在操作途中是没有释放锁的

这就是隐式获取两个锁(对象之间协作)..

这种方式也很容易就造成死锁…..

二、避免死锁的方法

避免死锁可以概括成三种方法:

  • 固定加锁的顺序(针对锁顺序死锁)
  • 开放调用(针对对象之间协作造成的死锁)
  • 使用定时锁–>tryLock()
    • 如果等待获取锁时间超时,则抛出异常而不是一直等待!

2.1固定锁顺序避免死锁

上面transferMoney()发生死锁的原因是因为加锁顺序不一致而出现的~

  • 正如书上所说的:如果所有线程以固定的顺序来获得锁,那么程序中就不会出现锁顺序死锁问题!

那么上面的例子我们就可以改造成这样子:


public class InduceLockOrder {

    // 额外的锁、避免两个对象hash值相等的情况(即使很少)
    private static final Object tieLock = new Object();

    public void transferMoney(final Account fromAcct,
                              final Account toAcct,
                              final DollarAmount amount)
            throws InsufficientFundsException {
        class Helper {
            public void transfer() throws InsufficientFundsException {
                if (fromAcct.getBalance().compareTo(amount) < 0)
                    throw new InsufficientFundsException();
                else {
                    fromAcct.debit(amount);
                    toAcct.credit(amount);
                }
            }
        }
        // 得到锁的hash值
        int fromHash = System.identityHashCode(fromAcct);
        int toHash = System.identityHashCode(toAcct);

        // 根据hash值来上锁
        if (fromHash < toHash) {
            synchronized (fromAcct) {
                synchronized (toAcct) {
                    new Helper().transfer();
                }
            }

        } else if (fromHash > toHash) {// 根据hash值来上锁
            synchronized (toAcct) {
                synchronized (fromAcct) {
                    new Helper().transfer();
                }
            }
        } else {// 额外的锁、避免两个对象hash值相等的情况(即使很少)
            synchronized (tieLock) {
                synchronized (fromAcct) {
                    synchronized (toAcct) {
                        new Helper().transfer();
                    }
                }
            }
        }
    }
}

得到对应的hash值来固定加锁的顺序,这样我们就不会发生死锁的问题了!

2.2开放调用避免死锁

在协作对象之间发生死锁的例子中,主要是因为在调用某个方法时就需要持有锁,并且在方法内部也调用了其他带锁的方法!

  • 如果在调用某个方法时不需要持有锁,那么这种调用被称为开放调用!

我们可以这样来改造:

  • 同步代码块最好仅被用于保护那些涉及共享状态的操作!


class CooperatingNoDeadlock {
    @ThreadSafe
    class Taxi {
        @GuardedBy("this") private Point location, destination;
        private final Dispatcher dispatcher;

        public Taxi(Dispatcher dispatcher) {
            this.dispatcher = dispatcher;
        }

        public synchronized Point getLocation() {
            return location;
        }

        public synchronized void setLocation(Point location) {
            boolean reachedDestination;

            // 加Taxi内置锁
            synchronized (this) {
                this.location = location;
                reachedDestination = location.equals(destination);
            }
            // 执行同步代码块后完毕,释放锁



            if (reachedDestination)
                // 加Dispatcher内置锁
                dispatcher.notifyAvailable(this);
        }

        public synchronized Point getDestination() {
            return destination;
        }

        public synchronized void setDestination(Point destination) {
            this.destination = destination;
        }
    }

    @ThreadSafe
    class Dispatcher {
        @GuardedBy("this") private final Set<Taxi> taxis;
        @GuardedBy("this") private final Set<Taxi> availableTaxis;

        public Dispatcher() {
            taxis = new HashSet<Taxi>();
            availableTaxis = new HashSet<Taxi>();
        }

        public synchronized void notifyAvailable(Taxi taxi) {
            availableTaxis.add(taxi);
        }

        public Image getImage() {
            Set<Taxi> copy;

            // Dispatcher内置锁
            synchronized (this) {
                copy = new HashSet<Taxi>(taxis);
            }
            // 执行同步代码块后完毕,释放锁

            Image image = new Image();
            for (Taxi t : copy)
                // 加Taix内置锁
                image.drawMarker(t.getLocation());
            return image;
        }
    }

    class Image {
        public void drawMarker(Point p) {
        }
    }

}

使用开放调用是非常好的一种方式,应该尽量使用它~

2.3使用定时锁

使用显式Lock锁,在获取锁时使用tryLock()方法。当等待超过时限的时候,tryLock()不会一直等待,而是返回错误信息。

使用tryLock()能够有效避免死锁问题~~

2.4死锁检测

虽然造成死锁的原因是因为我们设计得不够好,但是可能写代码的时候不知道哪里发生了死锁。

JDK提供了两种方式来给我们检测:

  • JconsoleJDK自带的图形化界面工具,使用JDK给我们的的工具JConsole
  • Jstack是JDK自带的命令行工具,主要用于线程Dump分析。

具体可参考:

三、总结

发生死锁的原因主要由于:

  • 线程之间交错执行
    • 解决:以固定的顺序加锁
  • 执行某方法时就需要持有锁,且不释放
    • 解决:缩减同步代码块范围,最好仅操作共享变量时才加锁
  • 永久等待
    • 解决:使用tryLock()定时锁,超过时限则返回错误信息

在操作系统层面上看待死锁问题(这是我之前做的笔记、很浅显):

参考资料:

  • 《Java核心技术卷一》
  • 《Java并发编程实战》
  • 《计算机操作系统 汤小丹》

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友

文章的目录导航:

Landsat 8/9 C2L2数据QA波段详解:从二进制解码到云、气溶胶、饱和度的实战避坑指南 本文详细解析了Landsat 8/9 C2L2数据QA波段的二进制编码结构,提供了从云检测、气溶胶影响到传感器饱和的实战避坑指南。通过Python和ENVI示例代码,帮助用户高效处理QA_PIXEL、SR_QA_AEROSOL和QA_RADSAT波段,提升遥感数据质量分析的准确性和自动化水平。 阅读详情

相关推荐

Google Earth Engine 教程——Landsat 8 影像集合去云分析QA波段和去云NDVI的影像

计算图像1和图像2中每一对匹配的波段的输入值的比特和。如果图像1或图像2只有一个波段,那么它将与另一个图像中的所有波段进行对比。输出的带子以两个输入中较长的命名,或者如果它们的长度相等,则以图像1的顺序命名。对于特征和特征集合,唯一支持的键是 "color",是一个CSS 3.0颜色字符串或 "RRGGBB "格式的十六进制字符串。图像的新掩码,是[0, 1]范围内的浮点值(无效=0,有效=1)。输出的图像保留了输入图像的元数据和足迹。该图层的不透明度,用0到1之间的数字表示,默认为1。

此星光明博客 2610

Google Earth Engine(GEE)实例代码学习三十五——利用Landsat8质量评估波段(QA)去云(Landsat8 Surface Reflectance))

Bit 0: Fill Bit 1: Clear Bit 2: Water Bit 3: Cloud Shadow Bit 4: Snow Bit 5: Cloud //创建一个函数进行去云掩膜处理 function maskL8sr(image) { //<<表示二进制左移几位 // 二进制第三位表示有云阴影,第五位表示有云。 var cloudShadowBitMask...

little00bee的博客 7801

一个简单的和死锁有关的程序

这是和死锁有关的问题,和简单的一个例子!

服务器判断自动还是手动连接网络,ADSL拨号上网实现服务器自动与网络连接

当多台计算机共享ADSL上网时,要使每一台计算机都通过手工方式来控制服务器与网络连接是比较麻烦的,但按照下面介绍的步骤就能实现服务器自动与网络连接.一、自动进行拨号当多台计算机共享ADSL上网时,要使每一台计算机都通过手工方式来控制服务器与网络连接是比较麻烦的,但按照下面介绍的步骤就能实现服务器自动与网络连接:1.在Windows XP操作系统的开始菜单中执行“运行”命令,输入 regedit,打...

weixin_36025345的博客 562

jlink v9刷固件修改序列号来修复弹窗

jlink v9弹窗警告修复j

weixin_40500627的博客 9367

Silvaco Atlas新手入门:从安装到第一个半导体器件仿真(附DeckBuild配置)

本文为Silvaco Atlas新手提供了一份从软件安装、DeckBuild环境配置到完成第一个半导体器件仿真的实战指南。通过构建一个经典的PN结二极管案例,详细讲解了Atlas仿真语句的语法、核心命令顺序以及结果调试与可视化方法,帮助初学者快速上手并理解TCAD仿真流程。

sql99的博客 332

使用C#实现ADSL自动拨号

在网络编程中,有时候会需要重新拨号建立网络连接(如Ad点击软件通过重新拨号形成有效点击) ,下面介绍两种程序中拨号的方法. 1、最简单的方法:使用RasDial命令 RasDial是Windows自带的命令,使用非常简单。实际使用是可将下面代码保存为一个批处理文件,然后直接运行或在程序里进行调用。 rasdial.exe/disconnect '断开连接 d...

weixin_30667301的博客 78

别再怕无霍尔BLDC了!手把手教你用反电动势过零检测搞定电机换向(附STM32代码片段)

本文详细介绍了无霍尔传感器BLDC电机的驱动方法,重点讲解反电动势过零检测技术及其在STM32上的实现。通过硬件电路设计、信号调理和软件算法优化,手把手教你完成电机换向控制,并提供实用的调试技巧和代码片段,帮助开发者快速掌握无霍尔BLDC驱动技术。

weixin_42522575的博客 492

主机用xp虚拟机是linux下ADSL设置上网教程

Product:VMwareWorkstation6.0绿色精简中文版(vmware.cn专版) 主机系统:MicrosoftWindowsXPProfessionalServicePack2 虚拟机系统:redflagLinux6.0桌面版 上网方式:网通ADSL(1M)

笑书生 1671

基于verilog的16QAM调制

思路1:正交调幅法——实现16QAM调制,可以理解为时相位相差90度的两个正弦波的4PAM叠加。 4比特输入经过2->4进制转化得到两路2比特输入,然后分别经过4PAM后叠加所得输出即为16QAM调制结果。 具体程序稍后编写。 思路2:复合相移法——可以借助前面编写的QPSK,相当于两路幅度不同的QPSK的叠加,比如幅度分别取1和3 。 思路1正交调幅法的设计方案: 两正弦波相位差...

weixin_30725467的博客 2929

基于STM32L4XX、HAL库的STS40-CD1B-R3温度传感器 驱动程序设计

/ HAL库需要左移一位。// 每2秒读取一次。// 等待测量完成 - 高精度模式大约需要15ms。// 执行软复位确保传感器处于已知状态。温度测量范围:-40°C ~ +125°C。湿度测量范围:0% ~ 100% RH。// 复位后需要等待至少1ms。// 初始化STS40传感器。// 读取温湿度数据。// 转换原始数据为实际值。// 发送读取序列号命令。// 读取序列号数据。湿度精度:±1.5% RH。

zhusl6688的博客 287

计算机睡眠状态网络是断开的吗,电脑进入睡眠模式会自动断网如何解决

电脑进入睡眠模式会自动断网如何解决今天给大家介绍一下电脑进入睡眠模式会自动断网的具体解决方法。1. 首先打开电脑,进入桌面,点击桌面左下角的开始图标。2. 在打开的开始菜单中,点击设置图标。3. 进入设置页面,找到“系统”选项,点击。4. 进入系统页面,找到”电源和睡眠“选项,点击。5. 接下来,在页面右侧,将网络连接下的在睡眠状态下也始终连接到网络的选项勾选上即可。以上就是电脑进入睡眠模式会自动...

weixin_29997223的博客 3万+

基于深度学习的智能监考系统(UI界面 + YOLOv8/v7/v6/v5代码 + 训练数据集)

行为检测与识别:能够自动识别考生在考试中的异常行为,如作弊、看手机、交头接耳等。实时监控:在考试期间,系统能够对考生的行为进行实时监控,及时发出警报。用户交互:通过简洁易用的UI界面,便于监考人员进行实时监控、查看警报和视频回放等操作。行为分析与反馈:系统能够识别出考生的违规行为,并提供反馈。本文详细介绍了如何构建基于YOLOv5的智能监考系统,从数据集的准备、YOLO模型的训练,到UI界面的设计与实现,展示了一个完整的深度学习监控系统。

YOLO 781

C#拨号代码(通过adsl拨号)

在Xp上运行正常,但在WIN7中好像不过。。好像可以使用 有时间可以研究下“C#使用DotRAS组件实现ADSL断网自动拨号” 在家一般都有一个MODEL   我们通过 ADSL即可拨号,下面是拨号程序 ,但没有判断现有的IP与之前 的IP 是否一样。。 以下代码是网找的,加上自己的修改。。。每次拨号的IP都会不同。。 上面的代码很乱,用下面的。 调用:

yeisman的专栏 2374

【即插即用模块】Transformer篇 | CVPR 2025 | D2T:双域特征融合,完美适配缺陷检测/小目标检测和分割等频域细节敏感的任务!

本文提出了一种基于小波和原型增强的双域Transformer(WPFormer)用于像素级表面缺陷检测。该模型通过Dual-domain Transformer (D2T)模块融合频域和空间域特征:小波增强交叉注意力(WCA)分解高低频特征并加权平衡,增强缺陷细节捕捉;原型引导注意力(PCA)生成全局原型向量强化关键信息聚合。实验表明,该模块在缺陷检测任务中性能优于现有方法,通过频域细节增强和全局依赖建模有效提升了复杂场景下的检测效果。代码已开源,适用于对频域敏感的目标检测和分割任务。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 1374

西南科技大学模拟电子技术实验二(二极管特性测试及其应用电路)预习报告

3、用二极管正向虚拟IV仪测出数据,并记录数据于虚表3和虚表4。1、按照指导书multisim仿真软件上画出三种模型电路图,1、按照指导书multisim仿真软件上画出三种模型电路图,1、按照指导书multisim仿真软件上画出三种模型电路图,表6 二极管三种模型参数测试表(电源电压=1.2V)2、用万用表测出数据,并记录数据于虚表1和虚表2。2、用万用表测出数据,并记录数据于虚表5和虚表6。表5 二极管三种模型参数测试表(电源电压=12V)二极管三种模型参数测试表(电源电压=12V)

Welcome To My6n Blog 4081

分析ADSL拨号中出现的错误代码 原因及其解决办法

在Windows XP系统李安旺拨号过程之中,往往会出现ADSL拨号错误,今天整理了一些常见的错误代码的原因分析及其解决办法。 Error 602 The port is already open 问题:拨号网络网络由于设备安装错误或正在使用,不能进行连接 原因:RasPPPoE没有完全和正确的安装 解决:卸载干净任何PPPoE软件,重新安...

weixin_33692284的博客 190

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

XP双网卡共享上网

方法一:XP系统:[开始]--[设置]--[网络和拨号连接],右击连接ADSL的本地连接,IP应该取自动,DNS可以自动,也可以设置为当地电信的。右击连接客户机的本地连接,IP应该取192.168.0.1,不要设置网关(有了网关,就变成网桥),主DNS取当地电信的,辅DNS取192.168.0.1。客户机IP取192.168.0.2,网关192.168.0.1,DNS与网卡2#相同。右

wangmj518的专栏 828

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

win7下ADSL自动断网问题

使用ADSL拨号上网时每隔一段时间会自动断线,断线前会跳出提示,单击保持连接可以继续,否则60秒后自动断线,原先在xp系统下无此问题,推断是win7下的网络设置问题,解法如 下:        右键任务栏上的网络连接图标--打开网络和共享中心--左边的更改适配器设置--属性--选项--挂断前的空闲时间设置为--"从不".        IE浏览器菜单栏上的工具--Internet选项--连接

打造核心知识库 1569

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

学会看懂ADSL指示灯 硬件故障解决一点通

硬件、软件故障是经常出现的问题,ADSL也不例外,而ADSL出现了故障,直接产生的结果就是网络状态不正常,或者是无法连入网络,下面我们就来看看ADSL在使用中可能会遇到哪些问题、故障,并看看相应的解决方案。 一、硬件设备故障 硬件设备故障是指包括ADSL“猫”、网卡、线路等设备出现的故障,而这些硬件上面的问题一般可以直接根据ADSL上面指示灯的状态来进行判断,首先我们...

weixin_34326558的博客 206

xp wifi android,安卓手机怎么共享XP的网络 无线wifi共享教程【详解】

安卓手机怎么共享XP的网络?Wi-Fi是一个无线网络通信技术的品牌,由Wi-Fi联盟(Wi-Fi Alliance)所持有。目的是改善基于IEEE802.11标准的无线网络产品之间的互通性。无线网络上网可以简单的理解为无线上网,几乎所有智能手机、平板电脑和笔记本电脑都支持无线保真上网。下面,我们就来看看无线wifi共享教程。xp系统wifi共享给安卓手机【万能方法】1.无线wifi共享:适用所有安...

weixin_32073733的博客 647

XP系统屏蔽五项网络功能,让速度飞起来

每一个windows xp用户都想让自己的电脑有着畅快的运行速度,而最终的结果往往并非如此!那么需要究竟怎样做?事实上,很多情况下就是因为这些设置不当的网络功能拖慢了系统启动速度,想想看,我们用到的东西还经常运行!所以当我们关掉这些用不到的功能时,是不是会好一些呢?答案是肯定的!   第一步:屏蔽自动分配功能    依次单击“开始”/“设置”/“网络连接”/“本地连接”,直接进入 “本地连

xihurs的专栏 996

联想笔记本ADSL拨号上网拔网线死机问题分析(转载)

 联想笔记本ADSL拨号上网拔网线死机问题分析现象描述:使用ADSL拨号上网,直接拔掉网线后系统死机,鼠标没有任何反应,必须强行关机重新启动系统。其它情况没有这种现象,比如:1、在网络连接里,右键断开;2、不通过adsl拨号上网。另ADSL拨号掉线的时候主机也死机。机器是联想昭阳E290,Windows XP系统。问题解决:在网上搜索,得知这是Broadcom网卡芯片某

881

华硕服务器联机中断,Windows 7间歇性地断开有线Internet / LAN连接

简而言之,我的Windows 7 Ultimate PC会间歇性地断开其Internet连接。为什么?背景:我的PC连接到直接连接到电话线的ADSL调制解调器/路由器。我还打开了路由器内的无线连接,以便笔记本电脑进行无线连接。每隔几个小时左右,在使用PC时,我发现我无法访问Internet,并且无法加载页面。最终,Windows 7将更新任务托盘中的网络图标,以在网络图标上显示感叹号。打开网络和共...

weixin_39605191的博客 1229
上一篇: 线程池你真不来了解一下吗?
下一篇: 给女朋友讲解什么是代理模式
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值