Java多线程(一)

目录

Java多线程(一)

线程与进程基本介绍

并发和并行基本介绍

CPU调度基本介绍

主线程基本介绍

创建线程对象与相关方法

继承Thread类创建线程对象

多线程在内存中运行的原理

Thread类中常用的方法

Thread类中关于线程优先级的方法

守护线程与Thread类中关于守护线程的方法

礼让线程与Thread类中关于礼让线程的方法

插入线程与Thread类中关于插入线程的方法

实现Runnable接口创建线程对象

使用匿名内部类创建线程对象

使用继承or接口创建线程对象

线程安全

线程安全引入

解决线程安全

同步代码块解决线程不安全

同步方法解决线程不安全

死锁

线程状态


Java多线程(一)

本章中的概念部分都只是为了后面的程序执行更好理解,更深层的概念移步到Linux进程部分(待更新)

线程与进程基本介绍

进程:在内存中运行的程序实例,一般一个程序代表一个进程

线程:进程中最小的执行单元,一般线程负责进程中程序的运行,一个线程至少存在一个线程,也可以有多个线程,当存在多个线程时,一般称为多线程程序

可以简单理解为:当一个程序加载到内存中后就会开启一个进程,当程序需要执行某一个功能时就会开辟一个线程,该线程就是程序与CPU交流的通道,一个功能对应着一个线程,一个线程对应着一个通道

并发和并行基本介绍

并发:在同一个时刻,多个CPU(多核CPU)同时执行指令任务

并行:在同一个时刻,一个CPU执行多个指令任务

在CPU是单核时,CPU看似在同一时刻执行多个任务,实际上是CPU在执行任务中进行的高速切换,因为速度快所以人很难感知到任务执行的先后顺序
现在CPU基本上都是多核,可以理解为多个CPU,所以可以同一时间处理多个任务,每一个CPU管一个任务,但是依旧存在着高速切换,只是频率相对于单核CPU会变小,所以现在的CPU在执行指令时一般都是并行和并发同时存在

CPU调度基本介绍

CPU调用一般分为两种:

  1. 分时调度:让所有线程轮流获取到CPU的调度权,并且相对平均分配每个线程占用的CPU时间片
  2. 抢占式调度:多个线程轮流抢占CPU的使用权(哪个线程抢到了CPU的使用权,哪个线程先执行),一般都是优先级高的线程抢到的概率大,但不代表使用权一定属于优先级高的线程
Java程序都是抢占式调用

主线程基本介绍

主线程:CPU和内存之间专门为Java中的main函数服务开辟的线程

创建线程对象与相关方法

在Java中,创建线程对象一共有两种方式:

  1. 普通类继承Thread类,重写Thread中的run方法
  2. 普通类实现Runnable接口,重写接口中的run方法

继承Thread类创建线程对象

继承Thread类后重写Thread中的run方法,该方法用于线程中执行的任务,例如循环等。创建完自定义线程类后就可以通过自定义类创建一个线程对象,使用该对象调用start()方法启动线程,例如:

// 自定义线程类
public class Thread01 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("Thread01..." + i);}}
}// 主线程
public class Test {public static void main(String[] args) {// 创建自定义线程类对象Thread01 t1 = new Thread01();// 调用start方法启动线程t1.start();// 在主线程中执行其他任务for (int i = 0; i < 10; i++) {System.out.println("main..." + i);}}
}

因为Java程序都是抢占式调用,所以会出现交替执行的情况,也会出现主线程先执行完,再执行自定义线程的任务

需要注意,不要对同一个线程对象多次调用 start方法,也不要显式调用 run方法,直接调用 run方法就不会被认为是线程启动执行任务

多线程在内存中运行的原理

在Java程序中,当存在多个线程时,对于主线程来说是一个栈空间,而其余线程相当于其他的栈空间,如下图所示:

两个线程相互抢占使用权,但是因为main函数有更大的概率抢到,所以可能出现主线程任务先执行完再执行自定义线程任务

Thread类中常用的方法

  1. void start()方法:启动进程,JVM会自动调用对应线程的run方法
  2. void run()方法:设置线程中的任务,该方法是Thread类实现了Runnable接口后重写的方法
  3. String getName()方法:获取调用对象的线程名称,默认情况下线程名称组成为:Thread+编号
  4. void setName(String name)方法:设置调用对象的线程名称
  5. static Thread currentThread():获取当前已经获取到CPU使用权的线程
  6. static void sleep(long millis):设置线程睡眠,参数表示睡眠毫秒数
需要注意, Thread中的 sleep方法会抛出异常,如果在自定义线程类中使用 sleep方法时,不可以使用 throws处理异常,只能使用 try...catch,但是如果在主线程则可以直接使用

基本使用实例:

// 自定义线程
public class Thread01 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + "..." + i);}}
}// 主线程
public class Test {public static void main(String[] args) throws InterruptedException {// 创建自定义线程类对象Thread01 t1 = new Thread01();// 调用start方法启动线程t1.start();// 在主线程中执行其他任务for (int i = 0; i < 10; i++) {Thread.sleep(1000L);System.out.println(Thread01.currentThread().getName() + "..." + i);}}
}

Thread类中关于线程优先级的方法

  1. void setPriority(int newPriority):设置调用对象的线程优先级,线程优先级越高,抢到CPU使用权的概率越大,但是概率大不代表一定可以抢到。Java中线程优先级有10个等级,其中1表示最小优先级,10表示最大优先级,默认优先级为5
  2. int getPriority():获取调用对象的线程优先级

基本使用示例:

// 自定义线程类
public class Thread01 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + "..." + i);}}
}// 主线程
public class Test {public static void main(String[] args) throws InterruptedException {// 创建自定义线程类对象Thread01 t1 = new Thread01();Thread01 t2 = new Thread01();// 设置/获取线程优先级t1.setPriority(1);t2.setPriority(10);System.out.println("t1.getPriority() = " + t1.getPriority());System.out.println("t2.getPriority() = " + t2.getPriority());// 调用start方法启动线程t1.start();t2.start();}
}

守护线程与Thread类中关于守护线程的方法

守护进程:守护线程表示当前线程的任务会随着所有非守护线程结束而结束,但是在非守护线程结束时,守护线程一般不会是立即结束,因为在非守护线程结束时需要与守护线程进行结束信号的通信,这段时间中守护线程依旧在执行

需要注意,当出现一个守护线程,多个非守护线程时,守护线程会等到所有非守护线程结束才会结束

在Java中,可以使用void setDaemon(boolean on)将调用对象所在的线程设置为守护线程或者取消设置守护线程,参数取值只有两种:true(开启守护线程)和false(关闭守护线程)

基本使用实例:

// 自定义线程
public class Thread01 extends Thread {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + "..." + i);}}
}// 主线程
public class Test {public static void main(String[] args) throws InterruptedException {// 创建自定义线程类对象Thread01 t1 = new Thread01();Thread01 t2 = new Thread01();// 设置t1进程为守护进程t1.setDaemon(true);// 调用start方法启动线程t1.start();t2.start();// 在主线程中执行其他任务for (int i = 0; i < 10; i++) {System.out.println(Thread01.currentThread().getName() + "..." + i);}}
}

礼让线程与Thread类中关于礼让线程的方法

礼让线程:默认情况下Java的线程对CPU使用权是抢占式,而礼让线程是为了让正在抢夺使用权的线程尽可能相对平衡(不是绝对平衡),从而达到二者交替执行

在Java中,设置礼让线程的方法为:static void yield()

基本使用实例:

// 自定义线程
public class Thread01 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {// 设置礼让线程Thread.yield();System.out.println(getName() + "..." + i);}}
}// 主线程
public class Test {public static void main(String[] args) throws InterruptedException {// 创建自定义线程类对象Thread01 t1 = new Thread01();Thread01 t2 = new Thread01();// 调用start方法启动线程t1.start();t2.start();}
}

插入线程与Thread类中关于插入线程的方法

插入线程:让调用对象所在线程尽可能优先执行完,再执行其他进程

在Java中对应插入线程的方法为:void join()

基本使用实例:

// 自定义线程
public class Thread01 extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName() + "..." + i);}}
}// 主线程
public class Test {public static void main(String[] args) throws InterruptedException {// 创建自定义线程类对象Thread01 t1 = new Thread01();Thread01 t2 = new Thread01();// 调用start方法启动线程t1.start();// 阻塞当前线程,等待t1线程执行完毕t1.join();// 在主线程中执行其他任务for (int i = 0; i < 10; i++) {System.out.println(Thread01.currentThread().getName() + "..." + i);}}
}

实现Runnable接口创建线程对象

本方法创建线程对象与继承Thread方式类似,但因为Runnable是接口,所以必须重写对应的run方法,使用实现类创建对象(目前不是线程对象),将该对象使用Thread中的构造方法:Thread(Runnable target)创建线程对象

// 自定义线程
public class Thread02 implements Runnable{@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "..." + i);}}
}// 主线程
public class Test01 {public static void main(String[] args) {// 创建实现类对象Thread02 t = new Thread02();// 实现类通过Thread构造函数创建线程类对象Thread t1 = new Thread(t);t1.start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);}}
}

如果想为线程设置名字,可以使用void setName(String name)方法,也可以使用构造函数,例如:

public class Test01 {public static void main(String[] args) {// 创建实现类对象Thread02 t = new Thread02();// 实现类通过Thread构造函数创建线程类对象Thread t1 = new Thread(t, "线程1");t1.start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);}}
}

使用匿名内部类创建线程对象

基本使用方式如下:

public class Test02 {public static void main(String[] args) {// 使用对象名调用start方法Runnable r = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "..." + i);}}};Thread t1 = new Thread(r);t1.start();// 使用匿名内部类new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + "..." + i);}}}).start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName()+"..."+i);}}
}

使用继承or接口创建线程对象

如果当前自定义线程类已经继承了其他类,则选择通过实现Runnable接口创建线程对象,否则使用继承创建线程对象,因为Java不支持多继承

如果需要多个线程对象使用共享同一个资源时,可以考虑使用实现Runnable接口的方式创建线程对象

线程安全

线程安全引入

当同一个数据被多个线程获取到时,就会出现线程安全问题

例如,在买票的过程中,一共有三个人一起买票,如果至少两个人同时拿到同一张票就代表出现了线程不安全

// 自定义线程类
public class Thread03 extends Thread{static int tickets = 10;@Overridepublic void run() {while (tickets > 0) {System.out.println("线程" + Thread.currentThread().getName() + "获取到第" + tickets + "张票");tickets--;}}
}// 主线程
public class Test03 {public static void main(String[] args) {Thread03 t1 = new Thread03();Thread03 t2 = new Thread03();Thread03 t3 = new Thread03();t1.start();t2.start();t3.start();}
}

例如下面的情况:

解决线程安全

在Java中,解决线程安全的方式就是给有线程不安全的代码加锁,并且必须是同一把锁,否则该锁无效。给线程加锁的方式有两种:

  1. 使用同步代码块,使用格式如下:
synchronized (唯一任意对象){// 出现线程不安全的代码
}
  1. 同步方法:包括静态同步方法和非静态同步方法,使用格式如下:
// 静态方法
权限修饰符 static synchronized 返回值类型 方法名 {// 方法体
}// 非静态方法
权限修饰符 synchronized 返回值类型 方法名 {// 方法体
}

给线程不安全的代码加锁后,当一个线程进入后就会「加锁」,此时其他线程无法再进入对应的代码,当前面的线程执行完毕后离开,该锁就会「解锁」,此时其他线程就会进入重复上面的过程,在此过程中,哪一个线程先执行取决于哪一个线程先抢到CPU的使用权

同步代码块解决线程不安全

以前面的买票为例,解决方案如下:

// 修改后的自定义线程类(使用继承+同步代码块)
public class Thread03 extends Thread {static int tickets = 100;// 任意对象加锁static Object obj = new Object();@Overridepublic void run() {while (true) {synchronized (obj) {if (tickets > 0) {System.out.println(Thread.currentThread().getName() + "..." + tickets);tickets--;}else {break;}}}}
}// 主线程
public class Test03 {public static void main(String[] args) {Thread03 t1 = new Thread03();Thread03 t2 = new Thread03();Thread03 t3 = new Thread03();t1.start();t2.start();t3.start();}
}

修改后的代码就可以解决线程不安全的问题

上面的代码也可以通过实现Runnable类的方式创建线程对象实现,例如下面的代码:

// 使用接口实现+同步代码块
public class Thread04 implements Runnable{int tickets = 100;Object obj = new Object();@Overridepublic void run() {while (true) {synchronized (obj) {if(tickets > 0) {System.out.println(Thread.currentThread().getName() + "..." + tickets);tickets--;}else {break;}}}}
}// 主进程
public class Test03 {public static void main(String[] args) {// 使用实现+同步代码块Thread04 tickets = new Thread04();new Thread(tickets).start();new Thread(tickets).start();new Thread(tickets).start();}
}

使用接口实现与继承的不同的是,锁对象和票成员不需要使用static修饰,因为此时三个线程共用一个ticketsobj成员,示意图如下:

同步方法解决线程不安全
  • 静态同步方法
以继承+同步方法为例

对于静态同步方法来说,其默认锁是对象类

// 使用继承+静态同步方法
public class Thread05 extends Thread{static int tickets = 100;// 静态方法public static synchronized void sale() {if(tickets > 0) {System.out.println(Thread.currentThread().getName() + "..." + tickets);tickets--;}}@Overridepublic void run() {while (true) {sale();if(tickets <= 0) {break;}}}
}
  • 非静态同步方法
非静态同步方法只能使用接口的方式创建线程对象,因为使用继承无法保证 this只指向一个对象

对于非静态同步方法,其默认锁是this

// 使用实现+非静态同步方法
public class Thread06 implements Runnable{static int tickets = 100;// 非静态同步方法public synchronized void sale() {if(tickets > 0) {System.out.println(Thread.currentThread().getName() + "..." + tickets);tickets--;}}@Overridepublic void run() {while (true) {sale();if (tickets <= 0) {break;}}}
}

死锁

前面解决线程安全时涉及到加锁,但是如果出现锁嵌套,就容易出现死锁问题,例如下图:

代码实现:

// 锁1
public class LockA {public static LockA lockA = new LockA();
}// 锁2
public class LockB {public static LockB lockB = new LockB();
}// 死锁
public class DieLock implements Runnable{private boolean flag;public DieLock(boolean flag) {this.flag = flag;}@Overridepublic void run() {if (flag){synchronized (LockA.lockA){System.out.println("if...lockA");synchronized (LockB.lockB){System.out.println("if...lockB");}}}else{synchronized (LockB.lockB){System.out.println("else...lockB");synchronized (LockA.lockA){System.out.println("else...lockA");}}}}
}// 主线程
public class Test05 {public static void main(String[] args) {DieLock dieLock1 = new DieLock(true);DieLock dieLock2 = new DieLock(false);new Thread(dieLock1).start();new Thread(dieLock2).start();}
}

线程状态

在Java中,并不是所有进程都在开始运行之后直接进入运行状态,常见的状态有6种,见下面表格:

线程状态

导致状态发生条件

NEW(新建)

线程刚被创建,但是并未启动。还没调用start方法。

Runnable(可运行)

线程可以在Java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操作系统处理器。

Blocked(锁阻塞)

当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。

Waiting(无限等待)

一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。

Timed Waiting(计时等待)

waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleepObject.wait

Terminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡,也可以调用过时方法stop()

对应状态图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/422326.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka【十三】消费者消费消息的偏移量

偏移量offset是消费者消费数据的一个非常重要的属性。默认情况下&#xff0c;消费者如果不指定消费主题数据的偏移量&#xff0c;那么消费者启动消费时&#xff0c;无论当前主题之前存储了多少历史数据&#xff0c;消费者只能从连接成功后当前主题最新的数据偏移位置读取&#…

信息安全数学基础(8)整数分解

前言 在信息安全数学基础中&#xff0c;整数分解是一个核心概念&#xff0c;它指的是将一个正整数表示为几个正整数的乘积的形式。虽然对于任何正整数&#xff0c;理论上都可以进行分解&#xff08;除了1只能分解为1本身&#xff09;&#xff0c;但整数分解在密码学和信息安全中…

实战千问2大模型第三天——Qwen2-VL-7B(多模态)视频检测和批处理代码测试

画面描述:这个视频中,一位穿着蓝色西装的女性站在室内,背景中可以看到一些装饰品和植物。她双手交叉放在身前,面带微笑,似乎在进行一场演讲或主持活动。她的服装整洁,显得非常专业和自信。 一、简介 阿里通义千问开源新一代视觉语言模型Qwen2-VL。其中,Qwen2-VL-72B在大…

使用虚拟信用卡WildCard轻松订阅POE:全面解析平台功能与订阅方式

POE&#xff08;Platform of Engagement&#xff09;是一个由Quora推出的人工智能聊天平台&#xff0c;汇集了多个强大的AI聊天机器人&#xff0c;如GPT-4、Claude、Sage等。POE提供了一个简洁、统一的界面&#xff0c;让用户能够便捷地与不同的AI聊天模型进行互动。这种平台的…

先攒一波硬件,过几年再给电脑升级,靠谱吗?想啥呢?

前言 最近有小伙伴发来消息&#xff1a;我可以今年先买电脑的部分硬件&#xff0c;明年再买电脑的另一部分硬件&#xff0c;再组装起来不就是一台电脑了吗&#xff1f; 这确实是一个很好的办法。 我还记得大学有个室友&#xff0c;从大一每个月省吃俭用&#xff0c;攒下的钱…

Linux学习笔记(黑马程序员,前四章节)

第一章 快照 虚拟机快照&#xff1a; 通俗来说&#xff0c;在学习阶段我们无法避免的可能损坏Linux操作系统&#xff0c;如果损坏的话&#xff0c;重新安装一个Linux操作系统就会十分麻烦。VMware虚拟机支持为虚拟机制作快照。通过快照将当前虚拟机的状态保存下来&#xff0c;…

力扣100题——贪心算法

概述 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种在解决问题时&#xff0c;按照某种标准在每一步都选择当前最优解&#xff08;局部最优解&#xff09;的算法。它期望通过一系列局部最优解的选择&#xff0c;最终能够得到全局最优解。 贪心算法的核心思想 贪心算…

Springboot中自定义监听器

一、监听器模式图 二、监听器三要素 广播器&#xff1a;用来发布事件 事件&#xff1a;需要被传播的消息 监听器&#xff1a;一个对象对一个事件的发生做出反应&#xff0c;这个对象就是事件监听器 三、监听器的实现方式 1、实现自定义事件 自定义事件需要继承ApplicationEv…

HashMap常用方法及底层原理

目录 一、什么是HashMap二、HashMap的链表与红黑树1、数据结构2、链表转为红黑树3、红黑树退化为链表 三、存储&#xff08;put&#xff09;操作四、读取&#xff08;get&#xff09;操作五、扩容&#xff08;resize&#xff09;操作六、HashMap的线程安全与顺序1、线程安全2、…

整型数组按个位值排序

题目描述 给定一个非空数组(列表)&#xff0c;其元素数据类型为整型&#xff0c;请按照数组元素十进制最低位从小到大进行排序&#xff0c;十进制最低位相同的元司 相对位置保持不变。 当数组元素为负值时&#xff0c;十进制最低位等同于去除符号位后对应十进制值最低位。 输…

Facebook的虚拟现实计划:未来社交的全新视角

随着科技的不断进步&#xff0c;虚拟现实&#xff08;VR&#xff09;正逐步成为我们日常生活的一部分。作为全球领先的社交平台&#xff0c;Facebook正在大力投入虚拟现实技术&#xff0c;以重新定义社交互动的方式。本文将深入探讨Facebook的虚拟现实计划&#xff0c;分析其如…

Mycat2原理介绍

Mycat介绍 Mycat原理 Mycat 核心配置 Scheam.xml 逻辑数据库和节点对应关系配置Server.xml mycat的连接配置Rule.xml. 分片规则 自动分片auto-sharding-long&#xff0c;比如0-10000节点1 &#xff0c;10001-20000节点2枚举分片sahrding-bt-intfile ,比如beijing节点1…

[数据集][目标检测]血细胞检测数据集VOC+YOLO格式2757张4类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2757 标注数量(xml文件个数)&#xff1a;2757 标注数量(txt文件个数)&#xff1a;2757 标注…

【数据库】MySQL-基础篇-SQL

专栏文章索引&#xff1a;数据库 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、SQL通用语法 二、SQL分类 三、DDL 1.数据库操作 1.1 查询所有数据库 1.2 查询当前数据库 1.3 创建数据库 1&#xff09;案例&#xff1a; 1.4 删除数据库 1.5 切换数据库…

discuz论坛3.4 截图粘贴图片发帖后显示不正常问题

处理方法 source\function 路径下修改function_discuzcode.php function bbcodeurl($url, $tags) 函数 if(!in_array(strtolower(substr($url, 0, 6)), array(http:/, https:, ftp://, rtsp:/, mms://,data:i) 这一句里增加 data:i 即可 function bbcodeurl($url,…

JAVA基础:抽象类,接口,instanceof,类关系,克隆

1 JDK中的包 JDK JRE 开发工具集&#xff08;javac.exe&#xff09; JRE JVM java类库 JVM java 虚拟机 jdk中自带了许多的包&#xff08;类&#xff09; &#xff0c; 常用的有 java.lang 该包中的类&#xff0c;不需要引用&#xff0c;可以直接使用。 例如&#xff1…

Redis面试题整理

Redis 1、Redis主从集群 1.1、搭建主从集群 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离 1.2、主从同步原理 当主从第一次同步连接或断开重连时&#xff0c;从节点都会发送psync请求&…

即插即用篇 | YOLOv8 引入组装式Transformer模块AssembleFormer | arXiv 2024

本改进已同步到YOLO-Magic框架! 摘要—早期检测和准确诊断可以预测恶性疾病转化的风险,从而增加有效治疗的可能性。轻微的症状和小范围的感染区域是一种不祥的警告,是疾病早期诊断的重中之重。深度学习算法,如卷积神经网络(CNNs),已被用于分割自然或医学对象,显示出有希…

mp3转文字要怎么处理?使用这4个工具就对了

MP3是音频当中比较常用的格式&#xff0c;如果像将其转换成文字内容&#xff0c;一般的语音转文字工具都是可以完成的。但是音频转换成文字的过程中&#xff0c;它的准确率是会受到像口音&#xff0c;语言&#xff0c;环境音等因素的影响的。所以大家如果想将自己的mp3语音转成…

INIC6081量产工具下载,initio6081开卡软件分享

国内固态硬盘常用&#xff0c;且有量产工具流传出来的主控厂商包括慧荣、群联、点序、英韧、得一微、瑞昱、联芸、迈威、国科、华澜微等等。 每个主控需要用各自对应的量产工具&#xff0c;不同的量产工具支持的闪存颗粒也有差异&#xff0c;因此要根据固态硬盘实际的主控型号…