JAVA学习线路:day10多线程[2]

Java 多线程学习总结归纳(附代码) 这是本人在学习Java 多线程时的总结归纳以及代码,希望对下载的同学有帮助! 立即下载

心得:
我是一名正在自学的java的即将毕业的大学生
总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好
所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了。希望我们可以一起加油,一起学习,一起交流。

day10【多线程】

一、Lock接口

1、能够说出Lock接口的特点

java.util.concurrent.locks.Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。

2、能够使用Lock接口的方法

Lock锁也称同步锁,加锁与释放锁方法化了,如下:

  • 接口实现类:java.util.locks.lock.ReentrantLock

  • public void lock():加同步锁。

  • public void unlock():释放同步锁。

使用如下:

public class Ticket implements Runnable{
	private int ticket = 100;
	//Lock接口实现类
	private Lock lock = new ReentrantLock();
	/*
	 * 执行卖票操作
	 */
	@Override
	public void run() {
		//每个窗口卖票的操作 
		//窗口 永远开启 
		while(true){
			lock.lock();
			if(ticket>0){//有票 可以卖
				//出票操作 
				//使用sleep模拟一下出票时间 
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//获取当前线程对象的名字 
				String name = Thread.currentThread().getName();
				System.out.println(name+"正在卖:"+ticket--);
			}
			lock.unlock();
		}
	}
}

二、线程通信,等待与唤醒

1、能够理解等待唤醒案例

包子案例:生产者和消费者

定义一个变量,包子铺线程完成生产包子,包子进行++操作;吃货线程完成购买包子,包子变量打印出来。
1. 当包子没有时(包子状态为false),吃货线程等待。
2. 包子铺线程生产包子(即包子状态为true),并通知吃货线程(解除吃货的等待状态)。
3. 保证线程安全,必须生产一个消费一个,不能同时生产或者消费多个。

案例代码:

包子铺类:变量flag只在类中使用,因此可以去掉get/set方法。

/**
 * 资源对象,包子
 * 被线程调用的
 *
 *
 *  flag =false 指示灯,标记
 *  指示线程,该做什么
 *  默认值false , 没有包子,需要生产线程进行生产,对变量count++
 *  生产线程,完成任务, 修改标志位= true (有包子),唤醒对方线程。
 *
 *  flag=true 指示线程,有包子,需要消费者线程进来消费,对变量输出打印
 *  消费已经完成,修改标志位 = false(无包子),唤醒对方线程。
 */

public class BaoZiPu {
    private int count;

    //定义布尔变量,标志位
    private boolean flag =false ;

    //get方法,被消费者线程调用,输出
    public synchronized void get() {
        //判断标志位,是否允许消费
        //flag是false,没有包子,不能消费
        //等,等生产完毕
       while (flag == false){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("消费第 "+count+" 个包子...");
        //修改标志位
       flag = false;
        this.notifyAll();//唤醒全部线程
    }
    //set方法,被生存者线程调用,++变量
    public synchronized void set() {
       while (flag == true){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        count++;
        System.out.println("生产第 "+count+" 个包子");
         flag = true;
        this.notifyAll();//唤醒全部线程
    }

生产者类:

/**
 * 生产者线程
 * 调用包子铺资源对象的方法set
 *
 * java.lang.IllegalMonitorStateException 无效的监视器状态异常
 * 同步(对象) 锁对象,专业名词是监视器
 * 线程通信的方法 wait(), notify() 必须依赖锁对象调用!!
 * 不是锁对象调用,抛出异常
 */
public class Product implements Runnable {
    //创建资源对象
    private BaoZiPu baoZiPu;
    public Product(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }

    public void run() {
        while (true) {
           baoZiPu.set();
        }
    }

消费者类:

/**
 * 消费者线程
 * 调用资源对象,包子铺方法get
 */
public class Customer implements Runnable {
    private BaoZiPu baoZiPu;
    public Customer(BaoZiPu baoZiPu){
        this.baoZiPu = baoZiPu;
    }
    @Override
    public void run() {
        while (true) {
            baoZiPu.get();
        }
    }
2、能够说出sleep和wait方法区别
  • sleep()是Thread类静态方法,不需要对象锁。
  • wait()方法是Object类的方法,被锁对象调用,而且只能出现在同步中。
  • 执行sleep()方法的线程不会释放同步锁。
  • 执行wait()方法的线程要释放同步锁,被唤醒后还需获取锁才能执行。

三、Condition接口

1、能够说出Condition接口的方法的特点

Condition接口方法和Object类方法比较

  • Condition可以和任意的Lock组合,实现管理线程的阻塞队列。
    • 一个线程的案例中,可以使用多个Lock锁,每个Lock锁上可以结合Condition对象。
    • synchronized同步中做不到将线程划分到不同的队列中。
  • Object类wait()和notify()都要和操作系统交互,并通知CPU挂起线程,唤醒线程,效率低。
  • Condition接口方法await()不和操作系统交互,而是让释放锁,并存放到线程队列容器中,当被signal()唤醒后,从队列中出来,从新获取锁后在执行。
  • 因此使用Lock和Condition的效率比Object要快很多。

四、线程池ThreadPool

1、能够理解线程池的思想

创建线程每次都要和操作系统进行交互,线程执行完任务后就会销毁,如果频繁的大量去创建线程肯定会造成系统资源开销很大,降低程序的运行效率。

线程池思想就很好的解决了频繁创建线程的问题,我们可以预先创建好一些线程,把他们放在一个容器中,需要线程执行任务的时候,从容器中取出线程,任务执行完毕后将线程在放回容器。

2、能够使用Executors类创建线程池

Callable接口类:

/**
 *线程执行的任务接口,类似于Runnable接口。
 *接口方法`public V call()throw Exception
 *线程要执行的任务方法
 *比起run()方法,call()方法具有返回值,可以获取到线程执行的结果。
 */
public class MyCallable implements Callable<String> {
    public String call()throws Exception{
        System.out.println("线程开启");
        return "线程结果字符串";
    }

实现类:

/**
 * java.util.concurrent.Callable<V>接口
 *
 *  V call() throws Exception;
 *  可以抛出异常,方法具有返回值
 *
 *  接口只能在线程池中使用
 *
 *  线程池对象 submit(  Callable接口 )提交线程任务
 *  方法的返回值是 Future接口,表示线程执行完毕后的返回值
 */
public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //线程池,提交任务,获取线程执行后的返回值
        ExecutorService es =  Executors.newFixedThreadPool(2);
        //接受submit方法的返回值
        Future<String> future =  es.submit(new MyCallable());
        //接口中的方法 get()获取线程的返回值
        String str = future.get();
        System.out.println(str);
    }

代码举例:需求:创建有2个线程的线程池,分别提交线程执行的任务,一个线程执行字符串切割,一个执行1+100的和。

实现Callable接口,字符串切割功能:

public class MyStringCallable implements Callable<String[]> {

    private  String str;

    public MyStringCallable(String str ){
        this.str = str;
    }

    @Override
    public String[] call() throws Exception {
        return str.split(" +");
    }
}

实现Callable接口,1+100求和:

public class MySumCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int x = 1 ; x<= 100; x++){
            sum+=x;
        }
        return sum;
    }
}

测试类:

 public static void main(String[] args) throws Exception {
     //创建有2个线程的线程池
     ExecutorService es = Executors.newFixedThreadPool(2);
     //提交执行字符串切割任务
     Future<String[]> futureString = es.submit(new MyStringCallable("aa bbb   cc    d       e"));
     System.out.println(Arrays.toString(futureString.get()));
     //提交执行求和任务
     Future<Integer> futureSum =  es.submit(new MySumCallable());
     System.out.println(futureSum.get());
     executorService.shutdown();
    }
3、能够说出Runnable和Callable接口的区别

相同点:两者都是接口;都可用来实现多线程程序;都需要调用Thread.start()启动线程;

不同点:

  1. 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
  2. Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

五、Time定时器

1、能够使用Timer类定时执行任务
/**
 * 定时器: 在指定的时间隔内,进行操作
 * java.util.Timer 实现定时器
 * 构造方法直接new 无参数
 * 启动定时器方法:
 * 定时器任务         开始时间        毫秒间隔
 * void schedule(TimerTask task, Date firstTime, long period)
 * TimerTask参数,抽象类,传递子类对象,重写run()
    */
   public class TimerDemo {
   public static void main(String[] args) {
       Timer timer = new Timer();
       //开启定时器
       timer.schedule(new TimerTask(){
           public void run(){
               System.out.println("定时执行");
           }
       }, new Date(),3000);
   }
   }

   /*class MyTask extends TimerTask{
   public void run(){
       System.out.println("定时执行");
   }
   }*/

这是我的公众号,希望大家可以关注,让我们一起做最好的自我。
我也会把我自学视频分享在上面,供大家一起学习。

CodeBull

2、TCGA数据处理(差异分析前处理) 注意:1、是R语言中用于读取文本文件并创建数据框的函数。它可以从文本文件中读取数据并将其存储为数据框的形式,每一列代表一个变量,每一行代表一个观察值。2、括号要成对,不能少了;3、file = 'TCGA-LIHC.htseq_counts.tsv'引号可以是单或双引号,建议单;4、逗号主要中英文,都是用英文模式才没错;5、.tsv文件类型必须要有,不能删除,否则读不进来;6、上面代码将TCGA-LIHC.htseq_counts.tsv文件读入并赋值给count1。 阅读详情

相关推荐

qt使用qxlsx实现xlsx、xls表格文件快速写入和读取

新年第二篇文章,收尾一个去年计划中发表文章和实现功能。

kbq的博客 1万+

Java-多线程技术学习线路

前言今日整理多线程学习的路线,供想学习多线程的同学参考,可以沿着这个线路由浅入深对多线程技术做全面了解,篇幅较长,耐心点看完,上菜咯。

fdg277137601的专栏 625

.NET适配HarmonyOS进展 1. 前言

目前国产化系统浪潮下,适配鸿蒙是中国软件大势所趋,.NET作为最适合开发客户端语言之一,适配鸿蒙系统(HarmonyOS Next)是目前.NET开发者最关心的事情。我目前业余时间正在移植Avalonia到HarmonyOS,去年在.NET Conf CN上分享过,目前又取得一点进展,所以本文把所有问题进行整合与大家进行分享。

2301_76476890的博客 1461

Java基础-多线程

Java多线程部分讲解,这里只复述了基础知识部分,此篇文章非常值得阅读,建议读完此篇再去看看JUC并发的篇章,也在后续的进阶的文章类!!

llx522的博客 370

DIY一个SM2262ENG 2TB Nvme固态硬盘,慧荣SM2262EN主控

网友订做的 材料: 慧荣科技的62en,2片1G 三星DDR4缓存,4颗PF29F04T2AOCTH1,8CE B17A。SM2262EN属于慧荣第二代PCIe SSD主控,支持PCIe G3×4通道和全新的NVMe 1.3规范、8个NAND通道设计,并提供完整固件设计,最大循序读取速度高达3.5GB/s,循序写入速度达3.0GB/s,随机读写则高达420K IOPS和420K IOPS。此外,还采用目前最先进的低功耗设计,无论是在待机还是在工作状态下,均展现超低功耗,有效减少30%的功耗,满足用户追求超

m0_55207244的博客 1万+

静态分析工具COBOT与Testbed对比

Testbed为规则检查工具的代表,市场占有量非常大,但随着时间的推移,大家从规则匹配转向了用静态分析工具检查Bug,所以规则检查型工具占有量比开始时候已经减少,但仍有一些比较落后的单位还在继续采购此类工具。3、通过对开源工程的测试,进行误漏报率的对比,发现COBOT(库博)的误漏报率相比Testbed较低,因COBOT主打国内市场,在众多军工单位进行大量试用及使用,吸取了众多单位的意见和建议,更加符合国内军工单位的使用习惯及测试要求。4、此外库博在功能上还可以进行计划任务,检测队列,检测并发的功能支持。

chengoodflower的博客 2054

java多线程学习之路

java多线程

youtiantin的博客 549

1. 迈进 SAP UI5 开发世界的第一步 - Hello World

SAP UI5 是一个用于开发企业级 Web 应用的前端框架,基于 HTML 和 JavaScript. 作为教程的第一步,我们需要了解最基础的 HTML 知识。 请大家在电脑上任意新建一个文件夹,将其命名,比如我取的名称为 Walkthrough. 进入 Walkthrough 文件夹,再新建一个文件夹名叫 01,代表本教程的第一个步骤。 进入 01 文件夹,新建一个 webapp 文件夹。这个名称是 web 应用约定俗成所使用的,大家都倾向于用这个名称,当然你要是想用其他名称也没有问题。......

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 9001

Java学习路线(20)——多线程

多线程

Zain_horse的博客 771

大模型安全研究论文整理 2026年版

知乎博主小红书博主GitHub数据集参考: 大模型越狱指令 (harmful questions) 数据集整理会思考的大模型更不听话,我的豆包失控了…让QwQ思考模型-不思考的小技巧qwen3的致命幻觉!大模型微调所有大模型都在讨好人类不要思考过程,推理模型能力能够更强丨UC伯克利等最新研究o3/o4-mini幻觉暴增2-3倍!OpenAI官方承认暂无法解释原因UC伯克利:让推理模型少思考,准确率反而更高了!一句话让DeepSeek思考停不下来,北大团队:这是针对AI的DDoS攻击慢思考准确率反降30%!普

CSPhD-winston的博客 2007

Dify框架面试内容整理-如何优化Dify的应用性能?

为1536维)可选用 PCA、FAISS 的量化压缩方法降低维度(如128、256、512);对知识库预览、任务流配置等页面,使用 nginx/cache-control 减少请求。API 响应耗时(P50/P95)、Token 使用量、缓存命中率、向量检索耗时;对 Prompt+输入内容计算 Hash,缓存相同请求的返回结果;使用占位符 + 函数拼接,按需组合 Prompt,而非静态长模板;数据量大时,应在构建索引前清洗冗余段落、统一格式,避免重复向量。维度越低,检索越快,但可能影响召回准确度,需平衡。

不务正业的猿 1548

Java多线程从基本概念到精通大神,大佬给我们铺平学习之路

Java 提供了多线程编程的内置支持,让我们可以轻松开发多线程应用。Java 中我们最为熟悉的线程就是 main 线程——主线程。一个进程可以并发多个线程,每条线程并行执行不同的任务。线程是进程的基本单位,是一个单一顺序的控制流,一个进程一直运行,直到所有的“非守护线程”都结束运行后才能结束。Java 中常见的守护线程有:垃圾回收线程、这里简要述说以下并发和并行的区别。并发:同一时间段内有多个任务在运行并行:同一时间点上有多个任务同时在运行。

老男孩的架构路 499

【音视频基础】一篇搞懂视频的各种封装格式

在现代多媒体处理中,视频封装格式扮演着至关重要的角色。不同的封装格式决定了视频文件的存储方式、兼容性以及功能特性。无论是观看高清视频、编辑电影剪辑,还是在互联网上流式传输内容,理解各种视频封装格式的基础知识都是必不可少的。在这篇文章中,我们将详细介绍常见的视频封装格式,探讨为什么需要这些格式,以及它们各自的功能和区别,帮助你在选择和使用视频格式时做出更明智的决定。WEBM理解各种视频封装格式的功能和区别对于选择合适的格式至关重要。

m0_62599305的博客 2476

JAVA学习线路:day09多线程[1]

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了。希望我们可以一起加油,一起学习,一起交流。 day09【多线程】 今日学习内容-2020.10.6day09【多线程】一、多线程和进程的概念1、说出进程的概念2、说出线程的概念进程与线程的区别二、多线程的创建-继承方式1、能够使用继承类的方式创建多线程2、问.

CodeBull_K的博客 377

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

JAVA学习线路:day07集合[2]

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了。希望我们可以一起加油,一起学习,一起交流。 day07【集合】 今日学习内容-2020.9.27day07【集合】Collections工具类1、使用集合工具类的常用方法2、使用Comparator比较器进行排序增强for循环1、使用增强for循环遍历集合和.

CodeBull_K的博客 237

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

JAVA学习线路:day12-IO流[2]

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/JavaNotes上了。希望我们可以一起加油,一起学习,一起交流 day12【IO流】 今日学习内容-2020.10.13day12【IO流】一、常用的编码表1.1 可以说出常用的编码表二、转换流2.1 如何使用OutputStreamWriter写数据到文件2.1.1 构造方法2.

CodeBull_K的博客 240

jre9下载 jdk9

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

JAVA学习线路:day06集合[1]

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了。希望我们可以一起加油,一起学习,一起交流。 day06【集合】 今日学习内容-2020.9.23-9.25day06【集合】对象数组Collection集合1、说出集合与数组的区别2、使用Collection集合的常用功能迭代器(Iterator接口)1、使.

CodeBull_K的博客 766

Java学习——Day08:多线程

1.线程简介 多任务:看起来是多个任务同时在做,其实本质上同一时间只做一件事,切换很快导致看起来同时多了多件事。 多线程:多条线路同时做多件事情,多条执行路径,主线程和子线程并行交替执行。 程序:程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。 进程:是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。 线程:一个进程中可以包含多个线程,线程是CPU调度和执行的单位。 【注意】:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多

zxzx666的博客 252

JAVA学习线路:day14-网络编程

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/JavaNotes上了。希望我们可以一起加油,一起学习,一起交流 day14 【网络编程】 今日学习内容-2020.10.16day14 【网络编程】一、网络编程入门1.1 可以说出软件的结构1.2 可以说出UDP和TCP协议特点二、TCP通信协议2.1 可以说出TCP协议下两个常.

CodeBull_K的博客 662

JAVA学习线路:day08集合[3]

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了。希望我们可以一起加油,一起学习,一起交流。 day08【集合】 今日学习内容-2020.10.5day08【集合】Map集合1、说出Map集合特点2、使用Map集合添加方法保存数据3、使用”键找值”的方式遍历Map集合4、使用”键值对”的方式遍历Map集合5.

CodeBull_K的博客 295

JAVA学习线路:day13-JDK8新特性

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/JavaNotes上了。希望我们可以一起加油,一起学习,一起交流 day13 JDK8新特性【Lambda、函数式接口、Stream流】 今日学习内容-2020.10.13day13 JDK8新特性【Lambda、函数式接口、Stream流】一、Lambda表达式1.1 理解函数式.

CodeBull_K的博客 722

JAVA学习线路:day16-枚举_xml

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/JavaNotes上了。希望我们可以一起加油,一起学习,一起交流 day16 【枚举、XML】 今日学习内容-2020.10.19day16 【枚举、XML】一、枚举1.1 如何自定义枚举常量二、XML2.1 可以说出XML的作用2.2 知道XML的组成元素三、XML约束3.1 可.

CodeBull_K的博客 426

Java学习day07-Java高级编程-多线程

Eclipse->IBM IntelliJ IDEA->JetBrains

qq_36820823的博客 524

最新Java基础系列课程--Day14-多线程编程

多线程(Multithread)是指在同一个程序中同时存在几个执行体,按几条不同的执行路径共同工作的情况

znzbs的博客 7890

JAVA学习线路:day15-注释_反射

心得: 我是一名正在自学的java的即将毕业的大学生 总结笔记是为了让自己更好的理解和加深印象。可能不是那么美观,自己可以看懂就好 所有的文档和源代码都开源在GitHub: https://github.com/kun213/JavaNotes上了。希望我们可以一起加油,一起学习,一起交流 day15 【注解、反射、lombok】 今日学习内容-2020.10.17day15 【注解、反射、lombok】一、类的加载器1.1 可以说出类加载器的双亲委派二、反射2.1 如何通过反射技术获取Class字节码.

CodeBull_K的博客 408

JAVA学习线路:day01面向对象(继承、抽象类)

day01面向对象【继承、抽象类】 今日学习内容-2020.9.16 继承 方法重写 this/super关键字 抽象类 类与对象 1、什么是类 类是现实事物的抽象,将现实事物描述成对应的类,其行为封装为方法,属性封装为成员变量。 2、什么是对象 对象是从类中得到的具体实例!在定义Person类并没有一个具体的人出现,而创建对象后,就会出现一个具体的人 继承 1、说出继承的概念 当要定义一个类(讲师)时,发现已有类(员工)和要定义的类相似,并且要定义的类属于已有类的一种时,可以将要定义类定义为已有类的子

CodeBull_K的博客 803
上一篇: JAVA学习线路:day09多线程[1]
下一篇: JAVA学习线路:day11-IO流[1]
CodeBull码牛
博客等级 码龄6年 14粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值