02_线程通信与线程池

线程池参数到底要怎么配?这可能是最好的答案 文章目录1 线程池快速回顾2 现有设置参数的方法及不足3 如何设置核心线程数(corePoolSize)4 如何设置最大线程数(maxPoolSize)5 如何改变等待队列长度 ???? Java学习:Java从入门到精通总结 ???? Spring系列推荐:Spring源码解析 ???? 最近更新:2022年1月8日 ???? 个人简介:通信工程本硕????、阿里新晋猿同学????。我的故事充满机遇、挑战与翻盘,欢迎关注作者来共饮一杯鸡汤 ???? 点赞 ???? 收藏 ⭐留言 ???? 都是我 阅读详情

线程通信

什么是线程通信

当多个线程共同操作共享的资源时,线程间通过某种方式互相告知自己的状态,以相互协调,并避免无效的资源争夺

线程通信的常见模型(生产者与消费者模型)
  • 生产者线程,负责生产数据
  • 消费者线程,负责消费生产者所生产的数据
  • 生产者生产完数据,应该等待自己,通知消费者消费;
  • 消费者消费完数据,也应该等待自己,通知生产者生产!
模型的实现
import java.util.ArrayList;
import java.util.List;

// 生产者消费者模型
// 需求:
// 3个生产者线程,负责生产包子,每个线程每次只能生产1个包子放在桌子上
// 2个消费者线程,负责吃掉包子,每个线程每次只能从桌子上拿1个包子吃
public class Test {
    public static void main(String[] args) {
        // 1. 创建一个桌子(注意,是只有一个!)
        Desk desk = new Desk();

        // 2. 创建3个生产者线程(3个厨师)
        new Thread(() -> {
            while (true) {
                desk.put();     // 这是厨师1抢到桌子后,需要做的事情
            }
        }, "厨师1").start();

        new Thread(() -> {
            while (true) {
                desk.put();     // 这是厨师2抢到桌子后,需要做的事情
            }
        }, "厨师2").start();

        new Thread(() -> {
            while (true) {
                desk.put();     // 这是厨师2抢到桌子后,需要做的事情
            }
        }, "厨师3").start();

        // 3. 创建2个消费者线程(2个客人)
        new Thread(() -> {
            while (true) {
                desk.get();     // 这是客人1抢到桌子后,需要做的事情
            }
        }, "客人1").start();

        new Thread(() -> {
            while (true) {
                desk.get();     // 这是客人2抢到桌子后,需要做的事情
            }
        }, "客人2").start();
    }
}

class Desk {
    private List<String> list = new ArrayList<>();
    //(本程序中的厨师1,厨师2,厨师3,客人1,客人2,这五个线程相互抢锁与陷入等待
    // 原因很简单,因为 this 就是它们的锁对象,而这个锁对象,正好是我们创建的一个桌子对象(我们就创建了一个桌子而已)
    // 所以不论哪个线程调用了桌子对象的什么方法,总之,先碰到桌子的人,就能先干自己的活

    // 放1个包子的方法
    public synchronized void put() {
        // 判断是否有包子
        try {
            String name = Thread.currentThread().getName();
            if (list.size() == 0) {
                Thread.sleep(2000);  // 模拟做包子花了2秒
                list.add(name + "做的那个包子");
                System.out.println(name + "做了一个包子");

                // 做完包子后,唤醒别人,自己沉睡
                this.notifyAll();
                this.wait();
            } else {
                // 检测到有包子,就不用做了
                // 直接唤醒别人,自己沉睡
                this.notifyAll();
                this.wait();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 拿1个包子的方法
    public synchronized void get() {
        try {
            String name = Thread.currentThread().getName();
            if (list.size() == 1) {
                // 有包子,直接开吃!
                Thread.sleep(1000);  // 模拟吃包子花了1秒
                System.out.println(name + "吃了" + list.get(0));
                list.clear();
                this.notifyAll();
                this.wait();
            } else {
                // 检测到没有包子,直接唤醒别人,自己沉睡
                this.notifyAll();
                this.wait();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

线程池

认识线程池
  • 线程池就是一个可以复用线程的技术

  • 不使用线程池的问题——用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的,而创建新线程的开销是很大的,并且请求过多肯定会产生大量的线程出来,这样会严重影响系统的性能。

如何创建线程池

临时线程什么时候创建

  • 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程

什么时候会开始拒绝新任务

  • 核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始拒绝任务
import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) {
        // 1. 通过 ThreadPoolExecutor 创建一个线程池对象
        /* public ThreadPoolExecutor(   int corePoolSize,  // 核心线程数量(核心员工)
                                        int maximumPoolSize,  // 最大线程数量(核心员工+临时员工)
                                        long keepAliveTime,  // 临时线程存活时间(临时员工辞退时间)
                                        TimeUnit unit,  // 设置存活时间的单位(配合上面一行的功能使用)
                                        BlockingQueue<Runnable> workQueue,  // 任务队列(客人座位的数量)
                                        ThreadFactory threadFactory,  // 线程工厂(招聘员工的hr)
                                        RejectedExecutionHandler handler)  // 任务拒绝策略(大家都在忙的时候的处理方法)
         */
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }
}
线程池处理 Runnable 任务
import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) {
        // 1. 通过 ThreadPoolExecutor 创建一个线程池对象
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());  // new ThreadPoolExecutor.AbortPolicy() 拒绝策略之一: 抛异常

        // 2. 创建任务对象
        Runnable target = new MyRunnable();

        // 3. 将任务提交到线程池中处理
        pool.execute(target);  // 线程池会自动创建一个新线程,自动处理这个任务,自动执行!
        pool.execute(target);
        pool.execute(target);  // 此行及其以上的两行,都是立刻被3个核心员工服务

        pool.execute(target);  // 剩下的4个任务,因为刚好设有4个座位,所以不会招募临时员工
        pool.execute(target);  // 因此,这4个任务只能默默地等待那3个正在忙碌的核心员工服务它们
        pool.execute(target);
        pool.execute(target);


//        pool.shutdown();  // 等着线程池的任务全部执行完毕后,再关闭线程池
//        pool.shutdownNow();  // 不管任务是否执行完毕,立即关闭线程池!
        // 补充:正常开发中,创建线程池的目的就是为了不断的服务别人
        // 所以我们不会停掉它的,所以上面两个命令用得比较少

    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程要执行的任务内容
        try {
            System.out.println(Thread.currentThread().getName() + " ===> 输出完毕!");
            Thread.sleep(999000);  // 线程暂停1000毫秒
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
线程池处理 Callable 任务
import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1. 通过 ThreadPoolExecutor 创建一个线程池对象
        ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());  // new ThreadPoolExecutor.AbortPolicy() 拒绝策略之一: 抛异常

        // 2. 使用线程处理 Callable 任务
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        // 3. 获取线程处理后的任务返回结果
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

    }
}

class MyCallable implements Callable<String> {
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() {
        // 线程要执行的任务内容
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += i;
        }
        return Thread.currentThread().getName() + "计算出了1-" + n + "的和是 " + sum;

    }
}
Executors 工具类实现线程池

Executors 是一个线程池的工具类,提供了很多静态方法用于返回不同特点的线程池对象

import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) throws Exception {
        // 1. 通过 Executors 创建一个线程对象
        ExecutorService pool = Executors.newFixedThreadPool(3);  // 3 : 三个核心线程可复用
        // 核心线程数量到达配置多少合适呢?
        // 计算密集型的任务:核心线程数量 = CPU的核数 + 1
        // IO密集型的任务:核心线程数量 = CPU的核数 * 2

        // 2. 使用线程处理 Callable 任务
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));

        // 3. 获取线程处理后的任务返回结果
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());

    }
}

class MyCallable implements Callable<String> {
    private int n;

    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() {
        // 线程要执行的任务内容
        int sum = 0;
        for (int i = 0; i < n; i++) {
            sum += i;
        }
        return Thread.currentThread().getName() + "计算出了1-" + n + "的和是 " + sum;

    }
}
大模型之Spring AI实战系列(二):Spring Boot + OpenAI 打造聊天应用全攻略 本篇文章是《Spring AI实战》专栏的第一篇开发入门文章,我们将借助一个完整的OpenAI聊天应用示例,详细介绍如何运用Spring Boot和Spring AI快速搭建一个支持OpenAI API的聊天服务,全面涵盖基础对话、流式对话、多提供商配置等核心功能。 阅读详情

相关推荐

抖音风控参数‘bd-ticket-guard-client-data’深度解析:从X.509证书到请求签名的完整链路

本文深度解析抖音风控参数‘bd-ticket-guard-client-data’的技术实现,从X.509证书体系到请求签名的完整安全链路。通过Python代码示例,揭示证书生成、签名算法及票据封装等核心机制,帮助开发者理解现代平台风控系统的多层防御架构设计。

weixin_42525738的博客 432

线程之间的通信&线程池&设计模式

概念:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,那么线程A与线程B之间就存在线程通信问题。简单一句话:设计模式就是经验的总结创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)

Cream336的博客 383

JeecgBoot漏洞利用工具解析:一键getshell原理与安全加固实践

在应用安全领域,远程代码执行(RCE)和文件上传漏洞是Web系统面临的高危威胁,其核心原理在于对用户输入的控制不足或安全校验缺失。攻击者通过构造恶意请求,可绕过系统边界,在服务器上执行任意命令或上传恶意文件,从而获取系统控制权。这类漏洞的技术价值在于揭示了应用层安全防护的薄弱环节,其利用方式自动化、集成化趋势明显,极大地提升了攻击效率。在低代码开发平台等快速构建的业务系统中,此类风险尤为突出。应用场景广泛覆盖安全测试、渗透评估与应急响应。本文聚焦于JeecgBoot平台的历史高危漏洞,深入解析其SQL注入、

weixin_30787531的博客 552

浅谈线程通信以及多线程的相关案例(阻塞式队列、线程池)

文章目录一、线程通信二、实现面包房案例三、阻塞式队列1.阻塞队列是什么2.生产者消费者模型3.阻塞队列实现四、线程池1.相关api线程池的工作流程五、定时器 一、线程通信 线程是并发并行执行,表现是线程间随机执行 线程是共享Java进程的内存,可以使用共享变量 为什么还需要线程通信? 由于线程之间是抢占式执行的,因此线程之间执行的先后顺序难以预知 但是实际开发中有时候我们希望合理的协调多个线程之间的执行先后顺序 假如有这样一个场景: Java中,设置进程的优先级(setPriority)不行!因为判断

m0_51405559的博客 439

微信开放标签wx-open-launch-app样式失效?手把手教你正确设置点击区域(附完整代码)

本文详细解析了微信开放标签`wx-open-launch-app`样式失效和点击无响应的常见问题,提供了完整的解决方案和代码示例。通过分析标签内部实现机制,指导开发者正确设置点击区域和样式,确保跨平台兼容性和用户体验优化。

joy55的博客 320

QGIS中高效处理CAD数据的两种实用技巧

本文详细解析了在QGIS中高效处理CAD数据的两种核心方法。针对DWG/DXF文件在QGIS中直接打开失败的问题,介绍了使用QGIS内置数据导入管理器进行标准化转换的流程,并重点推荐了功能更强大的Another DXF Importer插件,以更好地保留文字、块属性等复杂信息。文章对比了两种方法的优劣与适用场景,并提供了坐标系设置、中文乱码等常见问题的避坑指南,帮助用户根据数据需求选择最佳导入策略。

weixin_28363123的博客 117

java 线程通信和线程池

Executor线程池顶级接口,只有一个方法真正的线程池接口执行任务/命令,没有返回值,一般用来执行Runnable执行任务,有返回值,一般又来执行Callable关闭线程池基本实现了ExecutorService的所有方法默认的线程池实现类实现周期性任务调度的线程池Executors工具类、线程池的工厂类,用于创建并返回不同类型的线程池创建可根据需要创建新线程的线程池创建一个可重用固定线程数的线程池创建一个只有一个线程的线程池}核心池的大小。...

鑫阳的博客 1103

深度学习&故障诊断初学者 - 学习路线

针对初学者,一头雾水,不知如何学习,本文给出了一个学习路线 Python学习 - 打好编程基础 https://www.bilibili.com/video/BV1vA411b7Rn?spm_id_from=333.337.search-card.all.click B站免费课程 学到P49 建议时长 2周 深度学习理论 - 浅浅理解神经网络 https://www.bilibili.com/video/BV1FT4y1E74V?p=41 建议时长 2周...............

m0_47410750的博客 6万+

Java高级技术——多线程【2】

3个生产者线程,负责生产包子,每个线程每次只能生产1个包子放在桌子上2个消费者线程负责吃包子,每人每次只能从桌子上拿1个包子吃。 注意: 执行结果 什么是线程池?不使用线程池的问题线程池的工作原理 参数一:corePoolSize : 指定线程池的核心线程的数量。 参数二:maximumPoolSize:指定线程池的最大线程数量。 参数三:keepAliveTime :指定临时线程的存活时间。 参数四:unit:指定临时线程存活的时间单位(秒、分、时、天) 参数五:workQueue:指定线程池的任

nextStation12138的博客 918

YOLO11改进策略【独家融合改进】| EfficientViMBlock + LGAG + DySample

通过学习采样来学习上采样DySample。

Limiiiing的博客 362

2、MOSFET基本物理效应及其BSIM4模型解析

本文深入探讨了MOSFET的基本物理效应及其在BSIM4模型中的数学表述,涵盖门和沟道的几何结构、温度依赖性、材料模型选项、阈值电压计算、以及其他关键物理效应如LDD电阻、有限电荷厚度、有效迁移率等。同时解析了机械应力、邻近效应及布局依赖效应对MOSFET性能的影响,并通过参数表和建模流程提供了精确建模的指导,旨在帮助读者优化MOSFET器件性能与可靠性。

purple的博客 564

线程、多线程 、线程安全、线程通信、线程池 --java学习笔记

线程(Thread)是一个程序内部的一条执行流程程序中如果只有一条执行流程,那这个程序就是单线程的程序正在运行的程序(软件)就是一个独立的进程线程是属于进程的,一个进程中可以同时运行很多个线程进程中的多个线程其实是并发和并行执行的并发进程中的线程是由CPU负责调度执行的,但CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行CPU会轮询为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,这就是并发并行:在同一个时刻上,同时有多个线程在被CPU调度执行。

m0_71386740的博客 911

代码复现1——Matterport3d数据集下载

进入“Dataset Download”部分,下载申请书,填写之后发送到指定邮箱(matterport3d@googlegroups.com),之后会收到回信,回信中附有一个download_mp.py的脚本文件。,大小约15G,并不是所有的Mp3d datasets,所有大小约1.3T。下载完成后如下图所示:我这边显示大小为16.1G。

qq_44100524的博客 8052

【多线程】

在计算机中,进程是指正在执行中的一个程序,它由程序、数据和进程控制块组成。每个进程都有独立的地址空间,相互之间不能直接访问,是操作系统对程序运行进行管理的单位,每个进程都可以拥有多个线程。线程是指一条执行路径,它是进程中的一部分,可以与其他线程共享进程的资源和内存。线程是轻量级的进程,它比进程更快速,更容易创建和销毁。

2303_81066780的博客 1164

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

c++进程,线程,线程同步

进程是指一个程序的运行实例。

weixin_45459648的博客 1426

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

02_18_Java语音进阶||day18_Java基础小节练习(17-20部分)数据类型转换&运算符&方法入门、数组、网络通信概述&TCP协议、线程池&lambda表达式

第一部分 数据类型转换&运算符&方法入门 第一题 编写步骤: 定义类 Test1 定义 main方法 定义两个byte类型变量b1,b2,并分别赋值为10和20. 定义变量b3,保存b1和b2的和,并输出. 定义两个short类型变量s1,s2,并分别赋值为1000和2000. 定义变量s3,保存s1和s2的和,并输出. 定义一个char类型变量c1赋值为’a’,一个int类...

qq_40572023的博客 901

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

2024全网最全Java8 - 多线程专题(25秋招走起~)

临界区死锁(Deadlock)是指两个或多个进程或线程在竞争资源时,因彼此之间的互斥和等待而陷入无限等待的状态,导致它们都无法继续执行下去。死锁是一种程序设计或系统管理的错误,它会导致应用程序无响应或进程挂起,需要手动干预才能解决。互斥条件至少有一个资源是独占的,即一次只能被一个进程或线程占用。如果多个进程或线程同时需要访问这个资源,就会出现互斥条件。请求与保持条件进程或线程在持有至少一个资源的同时,又请求其他资源,但无法立即获得所需资源。这就会导致持有资源的进程或线程等待其他资源的释放,形成循环等待。

Wangzc_1116的博客 762

并发编程-02 多线程与线程池底层原理

Executors组织结构 拒绝策略 submit() 和 execute()的区别 submit()实现了execute()方法 void execute() 和 Future submit() 返回值不同 Java原生线程池 1.1 newCachedThreadPool() 参数定义: corePoolSize: 0 (无核心线程) maximumPoolSize:max (需要的话可以创建2^32-1个线程)[无休止的创建线程会导致OOM和CPU100%] keepAliveTime :6

csfun1的博客 5741

02-Java线程池

文章目录1 Java线程1.1 线程的状态1.2 Daemon线程1.3 理解中断1.4 线程间通信1.4.1 volatile和synchronized1.4.2 等待/通知机制1.4.3 管道输入/输出流1.4.4Thread.join( )1.4.5 ThreadLocal1.5 Thread.start( )启动原理1.5.1 JVM启动线程1.5.2 JVM创建线程1.5.3 JVM启动线程1.5.4 JVM线程回调1.5.5 总结2 Java线程池2.1 线程池实现原理2.2 线程池状态2.3

Seven_Year1的博客 340

02线程池的结构体描述信息

02线程池的结构体描述信息 01线程池原理剖析 02线程池的结构体描述信息 直接看代码,代码里有详细的注释。 //描述任务队列的结构体 typedef struct { void *(*function)(void *); /* 函数指针,回调函数 */ void *arg; /* 上面函数的参数 */ } threadpool_task_t; /* 各子线程任务结构体 */ /* 描

weixin_44517656的博客 280

c++11、14多线程从原理到线程池

C+11 14 17 多线程从原理到线程池为什么要使用多线程?

qq_24867003的博客 1541

线程池概述

同步服务层则会不断地将新的任务添加到同步排队中,有可能上层的任务非常多,而任务又是非常耗时的,这时,异步层中的线程处理不过来,则同步排队层中的任务会不断增加,如果同步排队层不加上限控制,则可能会导致排队层中的任务过多,内存暴涨的问题。从活动图中可以看到线程池的活动过程,一开始线程池会启动一定数量的线程,这些线程属于异步层,主要用来并行处理排队层中的任务,如果排队层中的任务数为空,则这些线程等待任务的到来,如果发现排队层中有任务了,线程池则会从等待的这些线程中唤醒一个来处理新任务。

m0_68224121的博客 1031

线程通信 线程状态 线程池 死锁 Volatile关键字

文章目录线程通信(代码几乎不用)线程状态线程池死锁Volatile关键字(不保证线程安全) 线程通信(代码几乎不用) 经典问题:生产者与消费者问题 生产不能过剩,消费不能停止(消息队列) this.notifyAll() this.wait() 线程状态 public class Thread { public static enum State { NEW, RUNNABLE, // 可运行 BLOCKED, // 锁阻塞

beOkWithAnything 203

多线程02

java中对线程通信、Lock、synchroized、阻塞队列、线程组、线程池、ForkJoinPool、ThreadLocal、线程安全的集合的相关知识点与简化业务场景的代码示例

qq_46147033的博客 1953

Linux的线程篇章 - 线程池、进程池等知识】

Linux学习笔记018 -- Linux的线程篇章 - 线程、进程、多线程、多进程等知识

m0_69455439的博客 1331

TinyWebServer项目笔记——02 半同步半反应堆线程池

3 public:4 //thread_number是线程池中线程的数量5 //max_requests是请求队列中最多允许的、等待处理的请求的数量6 //connPool是数据库连接池指针910 //像请求队列中插入任务请求1214 //工作线程运行的函数15 //它不断从工作队列中取出任务并执行之171921 //线程池中的线程数2324 //请求队列中允许的最大请求数2627 //描述线程池的数组,其大小为m_thread_number29。

qq_55527904的博客 1164
上一篇: 01_多线程与线程安全
下一篇: 03_并发并行与生命周期
code_stream
博客等级 码龄4年 1238粉丝 169原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值