Java并发编程(5)-Executor线程调度框架的使用

Java并发编程实战:深入探索线程池与Executor框架 线程池是一种基于池化思想管理线程的资源管理技术。它预先创建并维护一定数量的线程,当有任务到来时,直接从线程池中获取空闲线程执行任务,而不是每次都创建新线程。降低资源消耗:减少了线程的创建和销毁开销。提高响应速度:由于线程池中的线程已经预先创建,可以快速响应任务请求。提高系统吞吐量:通过复用线程,系统能够同时处理更多任务。Java的线程池与Executor框架为高效并发编程提供了强有力的支持。通过合理配置线程池参数、正确提交和处理任务,可以显著提升系统的性能和稳定性。 阅读详情


更多关于Java并发编程的文章请点击这里:Java并发编程实践(0)-目录页


Executor框架是在JDK5之后引入的一种线程调度类的集合,这些类的集合可以被统称为线程调度框架,本文将介绍Executor线程调度框架、各类线程池、Runnable和Callable< T >任务调度接口以及如何使用线程调度框架构造一个并发程序,最后介绍一下ExecutorCompletionService。
本文总结自《Java并发编程实践》第六章 任务执行 ,以及一些相关博客。

一、Executor线程调度框架

1.1、什么是线程调度框架

Executor框架是在JDK5之后引入的一种线程调度类的集合,这些类的集合可以被统称为线程调度框架,在这个框架体系中,任务的执行最小单元不是线程(Thread),而是任务(Task);而Executor可视为任务的执行器,它的作用是执行任务,进行任务的调度。常用的线程调度类和接口有:
Executors工厂类、Executor接口、ExecutorService接口、ExecutorCompletionService类、Runnable任务接口、Callable< T >响应式任务接口、Future< T >任务状态类、newFixedThreadPool定长线程池、newCachedThreadPool可缓存线程池、newSingleThreadExecutor单一线程池、newScheduledThreadPool可调度线程池。以上可简单地用结构图表示:
在这里插入图片描述

1.2、Executors

提供了一系列静态工厂方法用于创建各种线程池,可返回一个Executor对象或者ExecutorService对象,用以执行任务。

1.3、Executor

一个接口,其定义了一个接收Runnable对象的方法executor(Runnable command),用以执行Runabl任务。

1.4、ExecutorService

继承于Executor,是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法。

1.5、ScheduledThreadPoolExecutor

ScheduledExecutorService的实现,一个可定时调度任务的线程池,由Executors.newScheduledThreadPool返回,可用来代替Timer进行定时任务调度。

二、各类线程池

2.1、newFixedThreadPool

创建可重用且固定线程数的线程池,如果线程池中的所有线程都处于活动状态,此时再提交任务就在队列中等待,直到有可用线程;如果线程池中的某个线程由于异常而结束时,线程池就会再补充一条新线程。原理是有界的阻塞队列。



public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  //使用一个基于FIFO排序的阻塞队列,在所有corePoolSize线程都忙时新任务将在队列中等待
                                  new LinkedBlockingQueue<Runnable>());
}

2.2、newCachedThreadPool

创建可缓存的线程池,如果线程池中的线程在60秒未被使用就将被移除,在执行新的任务时,当线程池中有之前创建的可用线程就重用可用线程,否则就新建一条线程。



public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  //使用同步队列,将任务直接提交给线程
                                  new SynchronousQueue<Runnable>());
}

2.3、newScheduledThreadPool

创建一个可延迟执行或定期执行的线程池。

public class HeartBeat {
    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("HeartBeat.........................");
            }
        };
        executor.scheduleAtFixedRate(task,5,3, TimeUnit.SECONDS);   //5秒后第一次执行,之后每隔3秒执行一次
    }
}
2.4、newSingleThreadExecutor

创建一个单线程的Executor,如果该线程因为异常而结束就新建一条线程来继续执行后续的任务。

public static ExecutorService newSingleThreadExecutor() {
   return new FinalizableDelegatedExecutorService
                     //corePoolSize和maximumPoolSize都等于,表示固定线程池大小为1
                        (new ThreadPoolExecutor(1, 1,
                                                0L, TimeUnit.MILLISECONDS,
                                                new LinkedBlockingQueue<Runnable>()));
}

三、Runnable和Callable< T >任务调度接口

3.1、Runnable接口

每个任务调度接口都是另起一个线程作业,其中Runnable接口中的run方法不能返回参数,所以也称为无响应任务接口,结合上面的内容,我们来看以下简单的使用:

@Test
        public void demo1(){
            //使用Executors工厂类创建含10个线程的Executor执行器
            Executor executor = Executors.newFixedThreadPool(10);
            //创建一个无响应式任务
            Runnable task = new Runnable(){
                public void run(){
                    //具体任务实现
                    System.out.println("任务已执行");
                }
            };
            //执行任务
            executor.execute(task);
        }

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

3.2、Callable< T >接口和Future接口

Callable< T >接口用以实现有返回值的任务,需要注意的是,应该声明ExecutorService 接口类型来提交callable任务,并且获得了当前任务的状态声明Future对象,通过它获取到任务返回的值,如下:

 @Test
    public void demo2() throws ExecutionException, InterruptedException {
        //使用Executors工厂类创建含10个线程的ExecutorService执行器
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //创建一个响应式任务
        Callable<Integer> task = new Callable<Integer>(){
            public Integer call(){
                //执行有返回值的任务
                int i = 0;
                return ++i;
            }
        };
        //提交任务,获得任务状态类Futrue
        Future<Integer> future = executor.submit(task);
        //获得Future中的任务返回的响应值
        Integer response = future.get();
        System.out.println("任务执行,并返回了:"+response);
    }

在这里插入图片描述

四、使用线程调度框架构造一个并发程序

4.1、单线程模式

结合上述知识,我们可以构造一个简单的并发程序了。设想这样一个情景:小明早上起床了,他去煮水。。。
如果是单线程程序,比如只用main()方法执行,小明只能等水煮完了,才能去看书,听歌,如以下代码:

  public static void main(String[] args) {
            //第一个循环执行10次,其中i表示小明正在煮水的进度
        for (int i = 0; i < 10; i++) {
            System.out.println("煮水中:"+i);
        }

        //第二个循环,表示看书
        for (int i = 0; i < 5; i++) {
            System.out.println("看书中:"+i);
        }

        //第三个循环,表示听音乐
        for (int i = 0; i < 5; i++) {
            System.out.println("听歌中: "+i);
        }

        //...
    }

在这里插入图片描述

4.2、多线程调度模式-使用Runnable

上面的就是典型的单线程模式了,所有工作都要从头执行到尾,可是在现实中,小明可以变煮水边看书边听歌,这样就不会浪费时间,所以这里就要开启至少3个线程去做这3件事情:

@Test
   public void demo3() throws ExecutionException, InterruptedException {
       //使用Executors工厂类创建含3个线程的ExecutorService执行器
       ExecutorService executor = Executors.newFixedThreadPool(3);

       //创建一个任务1-煮水
       Runnable task1 = new Runnable(){
           public void run(){
               for (int i = 0; i < 10; i++) {
                   System.out.println(Thread.currentThread().getName()+"煮水中: "+i);
               }
           }
       };

       //创建一个任务2-看书
       Runnable task2 = new Runnable(){
           public void run(){
               for (int i = 0; i < 5; i++) {
                   System.out.println(Thread.currentThread().getName()+"看书中: "+i);
               }
           }
       };

       //创建一个任务3-听歌
       Runnable task3 = new Runnable(){
           public void run(){
               for (int i = 0; i < 5; i++) {
                   System.out.println(Thread.currentThread().getName()+"听歌中: "+i);
               }
           }
       };


       //提交3个任务给线程池去分配线程执行
       executor.execute(task1);
       executor.execute(task2);
       executor.execute(task3);

   }

在这里插入图片描述

可以看出,Executor线程调度框架分配了3个线程去分别执行了这3个任务,使得程序变成了并发的,提高了工作的效率。

4.3、多线程调度模式-使用Callable< T >

当然,我们也可以使用Callable< T >任务接口来完成上述的多线程调度例子:

 @Test
    public void fun14() throws ExecutionException, InterruptedException {
        //使用Executors工厂类创建含3个线程的ExecutorService执行器
        ExecutorService executor = Executors.newFixedThreadPool(3);

        //创建一个任务1-煮水
        Callable<Integer> task1 = new Callable<Integer>(){
            public Integer call(){
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName()+"煮水中 :"+i);
                }
                return null;
            }
        };


        //创建一个任务2-看书
        Callable<Integer> task2 = new Callable<Integer>(){

            @Override
            public Integer call(){
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName()+"看书中 :"+i);
                }
                    return null;
            }

        };

        //创建一个任务3-听歌
        Callable<Integer> task3 = new Callable<Integer>(){

            @Override
            public Integer call(){
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName()+"听歌中 :"+i);
                }
                return null;
            }

        };

        //提交3个任务给线程池去分配线程执行并获得线程状态对象
        Future<Integer> future1 = executor.submit(task1);
        Future<Integer> future2 = executor.submit(task2);
        Future<Integer> future3 = executor.submit(task3);
    }

五、ExecutorCompletionService

实现了CompletionService,将执行完成的任务放到阻塞队列中,通过take或poll方法来获得执行结果Future,然后调用Future的get方法即可获得响应的结果了。

@Test
    public void demo4() throws InterruptedException, ExecutionException {
        CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<>();
            //获得含有缓存线程池的Executor
        ExecutorService executor = Executors.newCachedThreadPool();
        //创建一个ExecutorCompletionService,将executor交给它管理
        ExecutorCompletionService completionService = new ExecutorCompletionService(executor);
        for (int i = 0; i < 10; i++) {
            int result = i;
            //创建一个响应式任务,循环执行10次
            Callable<Object> task = new Callable<Object>(){
                public Object call() throws InterruptedException {
                    return result;
                }
            };
            //提交任务
            completionService.submit(task);
            //将结果放入集合中
            Object o = completionService.take().get();
            list.add((Integer)o);
        }

        //将集合遍历
        for (Object o : list) {
            System.out.print((Integer)o+"\t");
        }


    }

在这里插入图片描述

六、ExecutorService的生命周期管理

ExecutorService继承自Executor接口,定义了一些生命周期的方法:

  public interface ExecutorService extends Executor {   
    void shutdown();   
    List<Runnable> shutdownNow();   
    boolean isShutdown();   
    boolean isTerminated();   
    boolean awaitTermination(long timeout, TimeUnit unit)   
            throws InterruptedException;   
    }  
6.1、shutdown方法

这个方法用于会强制关闭ExecutorService,它将取消所有运行中的任务和在工作队列中等待的任务。

6.2、shutdownNow方法

这个方法会强制关闭ExecutorService,它将取消所有运行中的任务和在工作队列中等待的任务,这个方法返回一个List列表,列表中返回的是等待在工作队列中的任务。

6.3、isShutdown方法

这个方法在ExecutorService关闭后返回true,否则返回false。

6.4、isTerminated方法

这个方法会校验ExecutorService当前的状态是否为“TERMINATED”即关闭状态,当为关闭状态时时返回true否则返回false。

6.5、awaitTermination方法

这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。

task:高效的线程池任务调度框架-开源 负责线程池中任务的高效并发执行。 1.您可以自定义线程池大小,以便您可以调整项目的性能要求。 2. 不用担心task-running-overtime,因为task框架已经实现了对超时任务的监控,一旦任务超时,任务监控器会将其从线程池中移除,还能帮你自动结束超时任务。 3.任务调度框架性能优良,如果任务队列为空,框架会自动进入等待状态,直到任务队列有任务要添加。 这样会大大减少CPU的消耗。 4.框架非常好用,例如:TaskQueue queue = new TaskQueue(); taskAssigner = new TaskAssigner(queue, 10); taskAssigner.start(); 队列。添加(任务); 立即下载

相关推荐

【全解析 | PTA】浙大版《Python 程序设计》题目集-第一章

Python浙大版PTA题解

wzhh_的博客 5529

常见分布式调度框架

elastic-job使用了quartz的调度机制,内部原理一致,他可以看作是quartz的一个扩展实现,使用注册中心(zookeeper)替换了quartz的jdbc数据存储方式,此外,elastic-job又支持分片等特殊功能。分布式任务调度SchedulerX是阿里巴巴自研的基于Akka架构的分布式任务调度平台,兼容开源XXL-JOB、ElasticJob,支持Cron定时、一次性任务、任务编排、分布式执行批量任务等功能,具备高可用、可视化、可运维、低延时等能力。绑定某个任务以及绑定机器。

a9757226的博客 2363

T2T基因组组装实战指南:从数据到完整染色体

本文详细介绍了T2T基因组组装技术的实战指南,从测序数据选择到完整染色体组装的全流程。重点解析了ONT ultra-long和PacBio HiFi测序技术的优势,以及如何攻克端粒和着丝粒等重复区域的组装难题。通过具体案例和实用技巧,帮助研究人员实现从数据到完整染色体的高质量组装。

weixin_29292535的博客 846

Java 实现多线程的三种方式

1、继承Thread类2、实现Runnable接口3、实现Callable接口1、增强程序的健壮性,将业务逻辑与线程调度分离2、线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

一步一步的前进 1194

随机森林的可解释性分析(含python代码)

随机森林的“黑箱”特性逐渐凸显,这使得我们难以理解和解释模型内部的工作机制。对于许多应用场景而言,仅仅获得高准确率的预测结果是不够的;了解预测背后的逻辑同样重要,特别是在医疗诊断、金融风险评估等领域。因此,对随机森林进行可解释性分析变得尤为重要。

m0_59257547的博客 3849

电动汽车远程监控与诊断软件:BMW ConnectedDrive EV远程监控二次开发_7.数据安全与隐私保护

数据加密是保护数据安全的重要手段之一。在电动汽车远程监控与诊断软件中,加密技术可以确保数据在传输过程中的安全性和完整性。常见的加密技术包括对称加密和非对称加密。

zhubeibei168的博客 886

java多线程要点速览(线程池,Executor框架)

合理地使用线程池能够带来3个好处:第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。线程池的主要处理流程:当提交一个新任务到线程池时,线程池的处理流程如下:1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。

jifashihan的博客 588

Oracle EBS Interface/API(29) - AP发票API

续上编文章《Oracle EBS Interface/API(28) - 客制化开发AP付款API》背景,介绍如调用官方提供标准AP发票API调用 用户界面 Invoices(Payables Manager->Invoices->Entry->Invoices) Open Interface Invoices(Payables Manager->Invoices->Entry->Open Interface Invoices) 快速参考 参考点 内容.

陈显平的专栏-Oracle EBS 1152

分布式定时任务调度框架

分布式定时任务框架的对比

代码让AI扣 9600

恒玄BES调试笔记-BES2500如何打开COMPEXP

打开Compressor and expander会占用资源,这个根据个人项目需求而定吧!打开方法,以及参数修改如下: config\best2300a_ibrt_anc\target.mk SPEECH_RX_COMPEXP ?= 1 apps\audioplayers\bt_sco_chain_cfg_default.c #if defined(SPEECH_RX_COMPEXP) /*****************************************************

leezs的博客 706

2025华为OD面试手撕代码真题目录及面试八股文

本专栏更新每年华为OD机试的高频手撕代码题,每个题目都会使用五种语言进行解答(C & C++& Java & Python & JS) 华为od机试,华为od机试真题,华为od机试E卷,华为odE卷,华为od机试真题E卷,华为OD,华为OD机试,华为OD机试真题,华为od机考,华为od机试D卷,华为od机试真题D卷,华为od手撕代码,华为od,华为od机试C卷,华为od e卷,华为2024e卷,od机试,2024E卷,华为OD机试E卷,什么是华为od,华为od介绍,全面了解华为od,2024华为od,如何备

KJ.JK 5万+

Java并发框架Executor

JavaSE5.0之后Executor内置在API中,极大的方便了并发编程。主要大部分:线程池,调度,Callable(延迟计算),线程安全数据结构(BlockingQueue,ConcurentMap...)。Effective Java的作者在介绍并发编程的时,建议读者使用Executor框架中的封装,二不是自己实现线程池,调度,wait(),notify(),应为在这个框架中都有成熟的封装...

tigerlchen的专栏 125

vue:npm安装pnpm报错,npm ERR! code ENOTFOUND,npm ERR! syscall getaddrinfo,npm ERR! errno ENOTFOUND详细排查解决!

vue2 vue3,npm install -g pnpm 安装出现错误,安装pnpm及解决安装失败问题,解决 npm无法安装pnpm问题,npm 安装 pnpm 时 报错 npm ERR! code ENOTFOUND,pnpm无法安装报错,vue npm install -g pnpm安装报错,request to http://registry.cnpmjs.org/pnpm failed, reason: getaddrinfo ENOTFOUND registry.cnpmjs.org,安装pnp

✅ 精选推荐文章 3609

java executor解读_Java-多线程框架Executor解读

概述在Java中,使用线程来异步执行任务。Java线程的创建与销毁需要一定的开销,如果我们为每一个任务创建一个新线程来执行,这些线程的创建与销毁将消耗大量的计算资源。同时,为每一个任务创建一个新线程来执行,这种策略可能会使处于高负荷状态的应用最终崩溃。Java线程既是工作单元,也是执行单元。从JDK1.5开始,把工作单元与执行机制分离开来。工作单元包括Runnable 和 Callable,而执行...

weixin_39828783的博客 179

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

java j2se1.5_用 J2SE1.5 建立多任务的Java应用程序

J2SE 5.0中的java.util.concurrent程序包提供了一个新的线程框架组件,这个框架组件处理了与建立、执行和管理线程相关的很多低层细节信息。在本文中我们将细致地了解一下它的重要特性。如果你使用C、C++或Java先前的版本进行多线程编程,就知道在代码中管理线程是多么头疼的事情。在单线程程序中,代码中引起应用程序失败的 bug每次都在同一个点出现。但是在多线程程序中,只有某些原因遇...

weixin_35837856的博客 130

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【JDK】:Executor框架

在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外

smile4lee的博客 1654

Executor--线程的执行器

Java SE5的java.util.concurrent包中的执行器(Executor)用来管理Thread对象,从而简化并发编程。关灯线程:public class LiftOffThread implements Runnable { protected int countDown = 10; private static int taskCount = 0; priva

pengkv的专栏 1152

Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,Completion

Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callablehttp://www.iteye.com/topic/366591

facome的专栏 514

Executor框架与线程池

Executor框架简介     在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了

yang7678287的专栏 302

Executor线程池实例

Executor 是 java5 下的一个多任务并发执行框架(Doug Lea),可以建立一个类似数据库连接池的线程池来执行任务。这个框架主要由三个接口和其相应的具体类组成。Executor、 ExecutorService 和 ScheduledExecutorService 。    1 、 Executor 接口:是用来执行 Runnable 任务的;它只定义一个方法- execute(R

太阳,月亮 4293

Java 线程池通俗详解

一、关于线程池: 1.采用线程池的优点 重用存在的线程,减少对象创建、消亡的开销,性能佳 。 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞 。 提供定时执行、定期执行、单线程、并发数控制等功能。 2.为什么引入线程池框架: new Thread()的缺点。 每次new Thread()耗费性能 。 调用new Thread()创建的线程缺乏管理,被称为野线程...

qq_24535745的博客 242

Executor

java5线程框架Executor的用法举例 分类: java基础2008-12-21 00:21 1672人阅读 评论(3) 收藏 举报 框架java任务threadexception数据库连接池    java.util.concurrent 与java线程框架有关的类主要都在这个包下。   java.util.concurrent.atomic 包含了不用加锁情况

loerier的博客 348

【Java并发编程】并发新特性—Executor框架与线程池(含代码)

转载请注明出处:http://blog.youkuaiyun.com/ns_code/article/details/17465497 Executor框架简介     在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动

秦时明月 1017

Java并发编程(19):并发新特性—Executor框架与线程池(含代码)

Executor框架简介

猫小妖的专栏 585

Java并发编程新纪元:探索Executor线程池框架

在Java并发编程领域,线程的创建与管理至关重要。传统通过new Thread()的方式在性能优化、资源高效利用及系统扩展性方面存在明显局限。鉴于此,本文将介绍Executor线程池框架,这一相较于传统线程创建方式更为优越的并发编程工具。Executor线程池框架通过复用线程、智能管理资源及灵活配置,显著提升了系统性能、优化了资源利用率,并增强了系统的可扩展性。

Rye的博客 2649

Java并发编程框架之Executor 框架

Java 并发编程框架是用于简化并发程序开发的一系列工具和库,它们提供了高层次的抽象来管理线程、同步机制和其他与并发相关的资源。随着Java语言的发展,这些框架不断进化,为开发者提供更加高效且易于使用的API。

物联网工程专业 - 软硬兼修 981
上一篇: Java并发编程(4)-同步容器和并发容器
下一篇: Java并发编程(6)-线程池总结
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

BoringRong

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

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

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

打赏作者

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

抵扣说明:

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

余额充值