CyclicBarrier和CountDownLatch使用上的区别

【VAX 小番茄安装详细步骤】 本文详细介绍了在VS2022环境下安装Visual Assist X(番茄助手)的步骤及常见问题解决方案。主要内容包括:安装前的兼容性设置(需修改为Windows7兼容模式)、安装流程(卸载旧版本、勾选对应VS版本、替换关键dll文件)以及常见问题处理(如安装失败、工具栏图标缺失等)。文章提供了完整的下载链接和操作截图,特别强调了安装失败后的清理方法(注册表、安装目录和残余文件删除)。最后给出了安装成功后的测试运行指引。 阅读详情

2018.12.12更新
在学习了CyclicBarrier之后发现,CyclicBarrier也可以实现跟CountDownLatch类似的功能,只需要在它的parties中多设置一个数,将主线程加入等待队列就可以了:

public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        int size = 3;
        // 设置参数时,线程实际执行数size+1,将main线程也加到等待队列中
        CyclicBarrier cyclicBarrier = new CyclicBarrier(size + 1);
        for (int i = 0; i < size; i++) {
            int index = i;
            pool.submit(() -> {
                try {
                    TimeUnit.SECONDS.sleep(index);
                    System.out.println("第" + index + "位运动员准备好了");
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        try {
        //主线程也加入等待
            cyclicBarrier.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(size + "位运动员都准备好了,可以起跑!");
    }

执行结果:
在这里插入图片描述

以下是原内容:


我在使用并发线程栅栏的时候发现了两种,分别是CyclicBarrier 和CountDownLatch。对于两者的对比的文章有很多,这里不再赘述。我来说下我的使用过程。

**需求:**有三位运动员,他们一起参加万米赛跑,但是他们准备的时间不同,要等他们都准备好了再开始一起跑。

使用CyclicBarrier 实现:

import java.util.concurrent.*;

public class RunTest {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        int size = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(size, () -> {
            System.out.println(size + "位运动员都准备好了,可以起跑!");
            pool.shutdownNow();
        });

        for (int i = 0; i < size; i++) {
            int index = i;
            pool.submit(() -> {
                try {
                    TimeUnit.SECONDS.sleep(index);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第" + index + "位运动员准备好了");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

结果:
这里写图片描述
可以看到,三位运动员准备的时间分别是1s,2s,3s。系统等到他们都准备好了,再发出起跑的信号。在这里CyclicBarrier 做法是在自己的构造器中new了一个runnable,等待其他线程都执行完,再执行此runnable中的代码。

我们再看看CountDownLatch怎么实现:

import java.util.concurrent.*;

public class RunTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newCachedThreadPool();
        CountDownLatch countDownLatch = new CountDownLatch(3);
        int size = 3;

        for (int i = 0; i < size; i++) {
            int index = i;
            pool.submit(() -> {
                try {
                    TimeUnit.SECONDS.sleep(index);
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("第" + index + "位运动员准备好了");
            });
        }
        countDownLatch.await();
        System.out.println(size + "位运动员都准备好了,可以起跑!");
    }
}

结果同上:
这里写图片描述

我们可以看到,countDownLatch是采取阻塞主线程的方法实现了线程的统一。他内部有一个计数器,我们在执行完一次线程任务的时候需要手动的减一个数,在主线程中使用 **countDownLatch.await()**监控计数器的状态,知道计数器计到0为止,再执行主线程的代码。

在实际的开发中,我个人比较倾向于第二种方法,因为使用起来简单,完全满足我的需求。

使用相对路径设置IAR的Additional include directories 以及 $PROJ_DIR$ 的用法 新建IAR工程时免不了要导入工程用到的头文件,那么导入头文时是用相对路径还是绝对路径呢?当然是相对路径了,因为绝对路径会有弊端,那就是,如果将来更换了工程放置的路径,那么这个相对路径就凉凉了,编译必然报错。所以最好还是用相对路径,那么相对路径怎么用呢? 请看以下 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 版权声明 本博文系广州欧科曼科技有限公司所有,转载请注明出处。 广州欧科曼科技有限公司致力于瑞萨MCU及周边相关产品开发设计。 ema 阅读详情

相关推荐

CountDownLatch 和 CyclicBarrier的区别与详解

CountDownLatch 的计数器是大于或等于线程数的,而CyclicBarrier是一定等于线程数 CountDownLatch 放行由其他线程控制而CyclicBarrier是由本身来控制的

wgq2020的博客 9316

别再死记硬背了!用51单片机的AD/DA和PWM,亲手做个简易示波器信号发生器

本文详细介绍了如何利用51单片机的PWM和AD/DA功能制作简易示波器信号发生器。通过PWM模拟DAC输出波形,结合XPT2046 ADC进行信号测量,实现方波、三角波和正弦波的生成与显示。项目不仅成本低廉,还能帮助电子爱好者深入理解51单片机的核心功能,是理论与实践结合的绝佳案例。

weixin_28675839的博客 265

java并发-CountDownLatch和CyclicBarrier区别、简单使用demo

文章目录CountDownLatch和CyclicBarrier区别 CountDownLatch和CyclicBarrier区别 CountdownLatch和CyclicBarrier的区别使用场景与具体实现 参考URL: https://zhuanlan.zhihu.com/p/139020914 CountDownLatch和CyclicBarrier使用上的区别 参考URL: https://www.cnblogs.com/geekdc/p/11541266.html CountDownLatch

西京刀客 3333

自动驾驶开发者必看:nuscenes数据集23类物体标注全解析(附避坑指南)

本文深入解析nuscenes数据集的23类物体标注系统,为自动驾驶开发者提供全面的标注规范解读和实战避坑指南。涵盖多模态数据组织、类别细分规则、属性系统应用技巧以及标注质量验证方法,帮助开发者高效利用这一标杆数据集提升模型性能。

weixin_29041767的博客 255

【项目实战】Qt6 录制屏幕、录制声音生成MP4、AVI、MA3等(完整源码,可直接编译使用)

本文将详细介绍如何利用Qt6多媒体模块中的QMediaCaptureSession、QMediaRecorder、QScreenCapture、QAudioInput、QMediaFormat等功能,实现对屏幕和声音的录制,并生成常见的媒体格式文件,如MP4、AVI、MA3等。我们将探讨如何利用这些功能来实现灵活的视频和音频参数设置,以满足不同需求下的录制和生成要求。我们将重点讨论如何配置视频和音频参数,包括分辨率、帧率、编解码器选择、音频采样率、声道设置等。

yegu001的博客 4939

CyclicBarrier 和CountDownLatch 的区别

(1)CountDownLatch 简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。 (2)cyclicBarrier 是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行! (3)CountDownLatch 的计数器只能使用一次。而CyclicBarrier 的计数器可以使用reset()方法重置。所以CyclicBarrier 能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计

siyuanwai的博客 572

Global Mapper与ArcGIS双剑合璧:自动化与半自动矢量化提取地物轮廓实战

本文详细介绍了如何结合Global Mapper的自动化批量提取与ArcGIS的半自动精细修整功能,高效完成地物轮廓矢量化工作。通过实战案例,阐述了利用Global Mapper快速抓取初步轮廓,再借助ArcGIS的ArcScan等工具进行精细化编辑和优化的完整工作流,有效提升地理信息数据处理效率。

weixin_29284657的博客 119

CyclicBarrier和CountDownLatch的区别

CountDownLatch是两组线程,第一组负责计数器减一,第二组是阻塞线程,当第一组线程将计数器减到0时,第二组线程才开始执行,放行是由第三方控制;CyclicBarrier是只有一组线程,只有当所有线程到达拦截点的时候,才会继续往下执行,放行是由一组线程本身控制。 CountDownLatch放行条件是大于或等于线程数;CyclicBarrier放行条件是等于线程数 CountDownLa...

xiaolyuh的专栏 1175

f_fs.c 初始化流程(进行中)

前言 之所以选择f_fs.c作为这系列的开始,因为usb在/driver/usb下面的内容实在太多太多,如果讲各种各样点会太分散了。所以决定切入点以实际使用为主,就是f_fs了,目前我了解这是做bulk裸传输使用的,具体的通信协议自己确定。 初始化部分 开始点从这个路径下说起, /drivers/usb/gadget/function/f_fs.c 然后f_fs.c第一个使用的是include/composite.h中的宏定义function #define DECLARE_USB_FUNCTION(_n

weixin_36406973的博客 1966

XGBoost原生接口和Sklearn接口参数详解

XGBoost原生接口和Sklearn接口参数详解

算法工程师 2654

CyclicBarrier和CountDownLatch的用法与区别

前言 CyclicBarrier和CountDownLatch这两个工具都是在java.util.concurrent包下,并且平时很多场景都会使用到。 本文将会对两者进行分析,记录他们的用法和区别。 CountDownLatch CountDownLatch是一个非常实用的多线程控制工具类,称之为“倒计时器”,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。 CountDownL...

Deegue 1万+

姿态传感器/陀螺仪之LSM6DS3TR-C应用原理图设计

LSM6DS3TR-C是一款由意法半导体(STMicroelectronics)推出的高性能、低功耗的惯性测量单元(IMU),集成了3轴加速度计和3轴陀螺仪,用于测量加速度、角速度以及设备的姿态和运动。

corlin6688的博客 871

CountDownLatch,CyclicBarrier和Semphore的使用及示例,区别

System.out.println(Thread.currentThread().getName()+"开始使用");System.out.println(Thread.currentThread().getName()+"使用结束");System.out.println(Thread.currentThread().getName()+"已经加入会议");2.当线程在使用资源前使用.acquire()获取使用资格,使用完成后调用release()唤醒其它等待资源的使用。

weixin_40711796的博客 1095

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

CountDownLatch和CyclicBarrier到底有什么区别

看了很多文章,没有说到重点。重点在这里>>

Royal_lr的博客 7820

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

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

CountDownLatch和CyclicBarrier区别

差一点点就挂了,还好我不要脸

3y 1839

深度学习工具包 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")

面试官:CyclicBarrier 和 CountDownLatch的区别是什么?

已重置),但这次没有额外动作。(打印消息),然后一起开始。都是 Java 并发包。

牛马baby的博客 1794

CountDownLatch 和CyclicBarrier的区别

区别点 CountDownLatch CyclicBarrier 概念 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。 N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。 强调点 重点在那《一个主线程》,他来协调其他N个线程执行完以后,主线程在做点其他的事 重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待...

靡不有初,鲜克有终。 2015

CyclicBarrier、CountDownLatch的用法和区别

特性计数器重置一次性,计数器到 0 后不能重置可重复使用,计数器可以重置用途主线程等待子线程完成任务多个线程相互等待,直到所有线程到达屏障点核心方法和await()适用场景主线程等待子线程完成任务分阶段任务,多个线程同步执行。

xuweilin的博客 558

CountDownLatch和CyclicBarrier的区别

在网上看到很多人对于CountDownLatch和CyclicBarrier的区别简单理解为CountDownLatch是一次性的,而CyclicBarrier在调用reset之后还可以继续使用。那如果只是这么简单的话,我觉得CyclicBarrier简单命名为ResetableCountDownLatch好了,显然不是的。 我的理解是,要从他们的设计目的去看这两个类。javadoc里面的描述是

kjfcpua的专栏 2万+

CountDownLatch和CyclicBarrier有什么区别?

CountDownLatch有时被称为“闭锁”,其作用相当于一扇门:在CountDownLatch达到结束状态之前,这扇门一直是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。当CountDownLatch到达结束状态后,将不会再改变状态,因此这扇门将永远保持打开状态。CountDownLatch可以用来确保某些活动直到其它活动都完成后才继续执行。 Cycli...

HD243608836的博客 626

CyclicBarrier 和 CountDownLatch 的区别?

适用于一个或多个线程等待某些操作完成的场景,适合一次性事件。:适用于一组线程需要互相等待的场景,适合多次重复使用的屏障点。选择合适的工具类可以根据你的具体需求来决定。如果你只需要等待某些操作完成,使用即可;如果你需要一组线程互相等待并且屏障点可以重用,使用会更加合适。

qq_33240556的博客 731

CyclicBarrier、Semaphore、CountDownLatch的区别,适用场景

`CyclicBarrier`、`Semaphore` 和 `CountDownLatch` 是 Java 并发包中用于线程协作的工具类,它们虽然都与线程同步相关,但设计目的和使用场景有显著差异。

小天一直在路上 850
上一篇: 记一次ES安装的采坑记录
下一篇: 【转】Java根据文件流判断文件类型
程序员青戈
程序员青戈 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄10年 3万+粉丝 250原创
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员青戈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值