springboot @schedule和@Async定时任务的异步 同步 多任务并发

一起来探究@Schedule定时任务在分布式产生的问题 定时任务的实现方式多种多样,框架也是层出不穷。本文所谈及的是 SpringBoot 本身所带有的实现定时任务的方式。以及采用这种方式,在分布式调度中可能会出现的问题,又针对为什么会发生这种问题?又该如何解决,做出了一些叙述。为了适合每个阶段的读者,我把前面测试的代码都贴出来啦~ 阅读详情

@schedule

@schedule注解参数有如下

       * cron:cron表达式,指定任务在特定时间执行;
       * fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
       * fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
       * fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
       * fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
       * initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
       * initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;

Delay的Rate区别在于Delay是任务完成之后多久执行, Rate是任务开始之后多久执行,一个是按完成时间计时 一个是按开始时间计时

@schedule原理

@schedule底层使用的是spring的任务调度线程池ThreadPoolTaskScheduler,ThreadPoolTaskScheduler底层使用的为JDK自带的ScheduledExecutorService(其实现类为ScheduledThreadPoolExecutor)

关于ScheduledThreadPoolExecutor(ScheduledExecutorService的实现)源码推荐文章https://www.jianshu.com/p/a39a89d28375,https://www.jianshu.com/p/8c4c160ebdf7这边就不在详细说明了 只做简单的说明

第一步 将任务添加到线程池的任务队列中

           此处知识点: 1 线程池:ScheduledThreadPoolExecutor 继承 ThreadPoolExecutor所以此处线程池为                                                                   ThreadPoolExecutor

                                  2 任务队列:此处任务队列为ThreadPoolExecutor中的一个无界延时阻塞队列(JDK队列推荐文章                                                     https://www.zybuluo.com/mikumikulch/note/712598)

第二步 线程池中的线程获取到延时队列中的任务第一次执行

第三步 延时队列中任务被线程执行完毕之后,重新根据我们传入的时间频率设置这个任务的时间放入到延时队列中,以此达到                任务被周期性反复的一直调用

因为任务执行完之后才被放入到队列中再次选取线程执行  所以定时任务线程池中不管有多少线程,只有一个线程执行这个任务,这个任务结束之后,也会重新选取一个线程再次执行

注意:在spring中的@schedule默认的线程池中只有一个线程,所以如果在多个方法上加上@schedule的话,此时就会有多个任务加入到延时队列中,因为只有一个线程,所以任务只能被一个一个的执行

在使用时我们可以按需配置定时任务线程池线程的大小,这个就改变了线程数量默认为1的线程池

@Bean("threadPoolTaskScheduler")
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setThreadNamePrefix("threadPoolTaskScheduler-");
        executor.setPoolSize(20);
        //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
        executor.setAwaitTerminationSeconds(60);
        //这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

@Async

此注解会将这个任务放入到一个异步线程中执行,不会阻塞主线程,可以用在一些比较耗时并且不用考虑返回值的一些操作中

比如有一个任务是3秒执行一次,一次任务执行需要8秒,若是吧这个任务加上@Async则这个任务就会放入到异步线程中去,

则这个任务不管这个任务执行的8秒还是依然会3秒执行一次,只是每次执行的结果需要8秒钟的延迟,但是结果我们一般是不考虑的

总结

① 默认@schedule  线程池默认只有一个线程,多个任务时串行   串行

@ 配置ThreadPoolTaskScheduler的@schedule 指定线程池中线程数量,多个任务并行  并行

@ 默认@schedule + @Aysnc 多个任务之间串行,单个任务非阻塞异步执行    串行+异步

@ 配置ThreadPoolTaskScheduler的@schedule+@Async  多个任务之间并行,单个任务非阻塞异步执行    并行+异步

【SpringBoot系列】Springboot 重点知识点最强整理 目录 1、springboot controller 单例 2、Springboot 环境变量配置 3、restful 接口 4、@ResponseBody 和 @RequestBody 的区别 5、@Schedule 6、async异步调用 7、request 的获取方式和线程安全 1、springboot controller 单例 Spring中 controller默认是单例的,因为单例所以不是线程安全的。 所以需要注意下面几点 不要在Controller中定义成员变量,可 阅读详情

相关推荐

c++实现异步线程池并详细分析线程池析构流程

多线程编程是提高程序性能和响应能力的关键技术之一,异步线程池作为多线程编程的一种有效实现方式,能够管理和复用线程资源,避免频繁创建和销毁线程带来的开销。在本文中,我们将深入探讨如何实现一个异步线程池。

2301_76564925的博客 1599

@Scheduled和@Async解析与自定义线程池

@Scheduled和@Async注解解析与自定义线程池

qq_39173672的博客 3215

基于STM32与OV7670的嵌入式视频监控系统设计与实现

本文详细介绍了基于STM32单片机与OV7670摄像头的嵌入式视频监控系统设计与实现。从硬件选型、电路设计到软件开发,涵盖了摄像头驱动、TFT显示优化及图像处理等关键技术,提供了实用的调试技巧和性能优化方案,为低成本、高效率的视频监控系统开发提供完整解决方案。

desk3的博客 802

Spring 异步和定时使用方法总结

https://www.cnblogs.com/duanxz/p/6782847.html 和 https://www.cnblogs.com/duanxz/p/6782933.html

weixin_36098377的博客 193

智能客服系统知识库构建:长尾问题解决方案全解析

智能客服系统知识库构建:长尾问题解决方案全解析

嗨,欢迎来到我的 优快云 博客小天地!一名深耕多年的技术发烧友。在这里,我将把日常工作中积累的宝贵经验,从复杂架构设计的精妙之处,到代码优化的实战技巧,毫无保留地分享给大家。 4112

Multisim实现555计时器模拟简易电子琴

一. 元器件介绍 这里用到的元器件有: DIgital power(VCC)数字电源 频率计数器(XFC) 示波器(XSC) ground 数字地 Capacitan 电容器 Resistor 电阻器 555_VIRTUAL 555计时器 触发按键(DIPSW)(DPST)(SPST)

是你呀星途的博客 2万+

Scheduled定时任务异步执行

Scheduled定时任务异步执行

wang20010104的博客 2274

推荐系统中召回率Recall计算方式附代码

Recall(召回率)是指在所有实际有交互的用户 - 物品对中,推荐系统成功预测出的比例。具体来说,设所有有交互的用户 - 物品对为S,推荐系统预测出的用户 - 物品对为T,则Recall的计算公式为:

优快云 精品推荐 1842

Spring使用@Async注解

本文讲述@Async注解,在Spring体系中的应用。本文仅说明@Async注解的应用规则,对于原理,调用逻辑,源码分析,暂不介绍。对于异步方法调用,从Spring3开始提供了@Async注解,该注解可以被标注在方法上,以便异步地调用该方法。调用者将在调用时立即返回,方法的实际执行将提交给Spring TaskExecutor的任务中,由指定的线程池中的线程执行。 在项目应用中,@Async调用线程池,推荐使用自定义线程池的模式。自定义线程池常用方案:重新实现接口AsyncConfigurer...

1 2036

数学建模学习(75):全局敏感性分析Morris 方法

敏感性分析 (SA) 是分析不同应用条件下模型行为的基本实践。提出了许多 SA 技术,从简单的筛选方法到计算成本高昂的基于方差的方法。本篇内容我们通过将 Morris 方法来对模型进行分析。

全栈川川 1万+

15、远程操作水下航行器(ROV)的非线性控制系统设计

本文探讨了远程操作水下航行器(ROV)的非线性控制系统设计,重点介绍了多变量PID控制、改进的PD控制和滑模控制三种方法。详细阐述了各控制策略的原理、建模与仿真过程,并通过对比分析其在稳态误差、振荡、抖振及跟踪效果等方面的性能表现。文章还提出了针对不同控制方法的优化建议,并给出了选择合适控制策略的决策流程,为ROV高精度运动控制提供了系统性解决方案。

sun99的博客 156

@Async @Scheduled的并发问题

问题场景:系统中@Scheduled设置的定时任务每两分钟执行一次,某一天上线了后发现@Scheduled不按时执行,经过排查发现是Spring内部某些内容共用了默认线程池,导致线程池资源不够而抢占资源导致。当时上线的是Kafka内容,引用了spring-kafka,经查发现其使用的线程池和@Scheduled是相同的默认线程池所以出现的问题,Kafka的大量并发持续占满线程池,导致定时任务抢占不到。 文章目录源码分析过程@Async@EnableAsync@EnbaleAsync的属性annotati.

爱清清的专栏 2037

火灾图像检测识别:cnn卷积神经网络 Adaboost 支持向量机 随机森林 决策树 完整代码数据

火灾图像检测识别:cnn卷积神经网络 Adaboost 支持向量机 随机森林 决策树 完整代码数据

862

使用@Schedule注解实现定时任务,多线程执行定时任务,Cron表达式详解

使用@Schedule注解实现定时任务,多线程执行定时任务,Cron表达式详解

樂小伍 1万+

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

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

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

@Schedule定时任务并行(异步)处理

最近项目中遇到一个问题 , 在SpringBoot中设置了定时任务之后 , 在某个点总是没有执行 . 经过搜索研究发现 , spring 定时器任务scheduled-tasks默认配置是单线程串行执行的 . 即在当前时间点之内 . 如果同时有两个定时任务需要执行的时候 , 排在第二个的任务就必须等待第一个任务执行完毕执行才能正常运行.如果第一个任务耗时较久的话 , 就会造成第二个任务不能及时执行...

qq_21036901的博客 3914

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

@Schedule 解决定时任务推迟执行

讲解三种 @Scheduled 解决定时任务进程堵塞,未及时执行的问题

Dily_Su的博客 6268

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Springboot @Schedule + 线程池配置可以轻松实现多个任务之间异步, 但是同一任务同步执行

Springboot @Scheduled 默认是单线程的, 也就是说当我们定义了多个定时任务时,如果有本应该是相同时间触发的定时任务, 会进行排队, 如果某个定时任务执行时间过长, 就会导致其他定时并未按照设置时间来触发执行。 异步任务可以部分解决这个问题, 在定时任务上再加上@Asyns注解,定时任务就会被作为异步任务多线程执行。 @Async @Scheduled(cron = "*/5 * * * * ?") public void mapDiagnosisExecutor() throws I

ElegantApple的博客 7046

SpringBoot定时任务@Schedule注解单线程阻塞

@Scheduled定时任务

weixin_42867178的博客 1987

【Java定时任务】SpringBoot+@Schedule注解

可以看到,最大线程数使用的是Integer.MAX_VALUE,即对于每一次定时任务的执行都会创建新的线程,并发环境下,会。【3】实现类上要有组件的注解@Component,@Service,@Repository。【1】cron表达式配置的任务如果执行超时,会从上一个任务结束的时间开始计算间隔。启用@EnableAsync注解,并在每一个定时任务方法上使用@Async注解。下一次的任务执行时间是从上一次定时任务结束时间开始计算。下一次的任务执行时间是从上一次定时任务开始时间开始计算。

神也在Cpoy 2122

SpringBoot定时任务+自定义线程池

背景 在真实的Java开发环境中,我们经常会需要用到定时任务来帮助我们完成一些特殊的任务,比如我最近写的晚上11点定时拉取第三方的数据入库,晚上12点清理脏数据等等。 如果我们使用SpringBoot来开发,那么定时任务将会变得非常简单。SpringBoot默认已经帮我们封装好了相关定时任务的组件和配置,我们只需要在相应的地方加上@Schedule注解就可以实现定时任务。 启动定时任务 SpringBoot项目只需要在启动类上加上@EnableScheduling即可开启定时任务 @SpringBootAp

god-jiang的博客 3490

SpringBoot @Schedule未按时执行问题解决

spring boot定时任务不执行

终身做学习,并予以实践 1633

Springboot集成定时器和多线程异步处理

需求:用@schedule标签进行定时处理逻辑,由于业务处理速度慢,需要每次执行逻辑放在不同的线程里异步执行 springboot集成多线程异步,直接上配置: /** * 线程池异步配置 */ @Configuration @EnableAsync public class ThreadExecutorConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor()

weixin_43469563的博客 852

@Schedule定时任务+分布式环境,这些坑你一定得注意!!!

来源:juejin.cn/post/7155872110252916766???? 欢迎加入小哈的星球,你将获得:专属的项目实战 /1v1 提问/Java 学习路线 /学习打卡/每月赠书/社群讨论新项目:《从零手撸:仿小红书(微服务架构)》正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,点击查看项目介绍;《...

犬小哈 331

Springboot @Schedule 多个定时任务积压解决

背景 应用中我们通常采用定时任务不断监听配置文件或者采集一些应用状态信息等等,这些任务通常间隔比较短,频次比较高。随着定时任务增多,定时任务偶尔出现了积压问题,即:定时任务总是顺序执行的,无法并行执行,此时当某个定时任务卡住时,会影响其他定时任务的执行,这样的结果不是我们想看到的。 现象 创建了两个定时任务 TestSchedule1 每 3 秒执行一次 TestSchedule2 每 2 秒执行一次 @Scheduled(cron = "0/3 * * * * ?") public

wozaizhe55 2781

@Schedule定时任务+分布式环境一些踩过的坑~

定时任务的实现方式多种多样,框架也是层出不穷。本文所谈及的是 SpringBoot 本身所带有的@Scheduled实现定时任务的方式。以及采用这种方式,在分布式调度中可能会出现的问题,又针对为什么会发生这种问题?又该如何解决,做出了一些叙述。为了适合每个阶段的读者,我把前面测试的代码都贴出来啦~

java_121388的博客 936
上一篇: Httpclient4.5详解之源码解析和使用四: 连接池内连接的打开和socket绑定
下一篇: 彻底理解javac命令-cp参数
且行且珍惜、
博客等级 码龄12年 12粉丝 34原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值