当前位置: 首页 > news >正文

【JavaEE初阶】认识线程(Thread)

目录

🌾 前言

🌾 了解线程

🌈1.1 线程是什么?

🌈1.2 一些基本问题 

🌾2、创建线程的方式

🌈 2.1 继承Thread类

🌈 2.2 实现Runnable接口并重写run()方法

🌈 注意:多个线程的写法

🌾3、多线程编程的意义

🌾4、线程的类与常用方法

 🌈 4.1 构造方法

 🌈 4.2 Thread类的几个常见属性

 🌾5、线程的状态


🌾 前言

        在学习之前,我们先简单的了解一下计算机中的常见的概念。

         1、冯诺依曼结构体系

        现代的计算机大多遵循冯诺依曼体系结构。主要由运算器,控制器,存储器,输入设备,输出设备组成。

        2、操作系统

        操作系统是一组做计算机资源管理系统的统称。常见的操作系统由Windows系列,Linux系列,OSX系列,ISO系列,Android系列。操作系统的作用主要有:(1)向上为应用程序提供一个稳定的运行环境;(2)向下管理所有的硬件设备;(3)为用户提供一个人机交互的界面。

        3、进程

        每一个运行起来的程序(软件),操作系统都会以进程的形式将他们管理起来在操作系统中,每一个进程被描述为一个PCB(进程控制块抽象)一个PCB中主要包括:PID,内存指针,文件描述符表,进程的优先级,进程的状态,上下文信息和记账信息。

        CPU分配 -> 进程调度:假设大部分场景下都是单CPU单核的计算机。操作系统对于CPU资源的分配,采用的是时间模式:不同的进程在不同的时间段去使用CPU资源。

        内存分配 ->内存管理:操作系统对内存资源的分配,采用的是空间模式:不同的进程使用内存中的不同区域,互相之间不会干扰。

        4、虚拟内存空间

        进程启动之后会申请内存空间,正常情况下是没有问题的。但是可能会出现一些特殊情况,比如C++中的野指针等。因此实际中,操作系统中有一个模块叫做MMU,MMU会给每个进程分配一个虚拟内存地址,这个地址和真实的物理内存之间建立映射关系。当进程越界访问内存空间时,MMU直接会进行拦截,起到了一个校验的作用,不会对真实的物理内存造成影响。

        存在的问题:但是由于MMU的限制,导致不同进程之间不能够互相访问内存,所以如何实现进程之间的数据共享,从而达到“信息交换”的需求?针对这一问题,进程间通信的需求应运而生。目前,主流操作系统提供的进程通信机制主要有:管道,共享内存,文件,网络,信号量,信号。

   问题:并发与并行的区别?

        在一个处理器上不停横向的轮动叫做并发,在多个处理器上执行叫做并行。通俗解释就是:并发是:一会干这件事,一会干那件事,但其实同一时刻只能干一件事;并行是:一边干这件事,一边干那件事,在同一时刻干多件事,真正意义上的同时进行,在编程方面,我们统一称为并发编程。


🌾 了解线程

      🌈1.1 线程是什么?

        一般多进程用来处理一个很大或者很复杂的任务。当进程启动的时候,需要申请内存,申请文件资源,将PCB加入到链表中;当进程结束的时候,需要释放文件,释放内存,从链表中删除PCB。但是在这个过程中申请和释放资源的操作是十分耗时的。因此为了解决资源消耗的问题,提出了一个轻量级进程的概念(线程)。在创建线程的时候使用的是进程创建时申请到的所有资源,线程只需要关注要处理的任务即可。

        举个例子:比如张三设计了一些皮包,他要去开一个工厂。他需要做以下一些事情:、

(1)去工业园区申请地皮,水电,仓库等(花了一个月的时间和几十万的钱);

(2)修建厂房和基础设施(花了几个月和几十万的钱);   

(3)购买生产设备和原材料,招工(花了一周和几万块钱);

(4)开始生产。 

        主要关注两者之间的对应关系!

        🌈1.2 一些基本问题 

       ❓ 问题1:进程与线程之间的区别?(面试题)

        (1)对于一个进程而言,必然会有一个线程(主线程);

        (2)进程是申请系统资源的最小单位,线程是CPU调度的最小单位;

        (3)进程之间互不影响,线程使用的是进程统一申请来的资源,线程之间可以相互影响。

       ❓ 问题2:  使用多线程编程的原因?       

        (1)为了充分利用CPU的资源       

        (2)利用轻量级进程的特性来减少系统性能的开销:            

                 线程创建的效率比进程高; 

                 线程销毁的效率比进程高; 

                 线程调度的效率比进程高

        ❓ 问题3:使用多线程存在的问题?

        当线程数量增大到一定程度之后,可能会给CPU调度带来负担,出现资源抢夺的问题,就会出现一些线程不安全的现象。

                


🌾2、创建线程的方式

    🌈 2.1 继承Thread类

        三部曲:继承Thread来创建一个线程类 -> 创建MyThread的实例 -> 使用start()方法启动线程

        (1)正常写法

public class Demo1_createThread {public static void main(String[] args) {Thread t = new MyThread();t.start();while (true){System.out.println("main thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
class MyThread extends Thread{@Overridepublic void run() {while (true){System.out.println("这里是线程运行的代码");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

 (2)使用匿名内部类的写法

    public static void main(String[] args) {//匿名内部类的形式Thread t = new Thread(){@Overridepublic void run() {while (true){System.out.println("生产生产生产...金币金币金币...+1+1+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}};//启动进程t.start();}

🌈 2.2 实现Runnable接口并重写run()方法

 三部曲:实现Runnable接口 -> 创建Thread类实例,将Runnable对象作为其目标参数 -> 使用start()方法启动线程

注意:在调用start()方法后,JVM会调用系统API,并在系统中生成一个PCB来执行run()方法中的代码。

(1)正常写法

public class Demo2_createRunnable {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t = new Thread(myRunnable);t.start();while (true){System.out.println("main thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
class MyRunnable implements Runnable{@Overridepublic void run() {while (true){System.out.println("这是线程运行的代码");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

注意:两个线程并不是有序的交替运行,因为CPU的调度是随机的。线程的执行是“抢占式执行”。

(2)使用匿名内部类的写法

     public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while (true){System.out.println("生产皮包,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});//开启线程t.start();}

(3)使用Lambda写法

public static void main(String[] args) {//Lambda表达式的使用条件就是该接口必须是一个函数式接口//比如Runnable接口就是一个 FunctionalInterface:所谓的函数式接口就是里面只有一个方法。比如(Runnable接口)中只有一个run();//怎么用Lambda表达式呢?()里写run方法的所有参数名,不需要参数类型,然后一个->即可。后面是正常的函数的功能实现Thread t = new Thread(()->{while (true){System.out.println("生产皮包,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//开启线程t.start();}

❓ 问题:使用Runnable  定义任务的好处?

(1)解耦,将定义线程与定义任务分开。(其中解耦的意思就是将不同的功能都给分开,如果要修改或者查找相应的功能的时候可以在指定的位置找)

(2)将创建线程与定义任务分开,以便修改代码时,可以统一修改。

🌈 注意:多个线程的写法

public class Demo3_multiRunnable {public static void main(String[] args) {//创建任务的对象MyRunnable1 myrunnable1 = new MyRunnable1();MyRunnable2 myrunnable2 = new MyRunnable2();//创建生产皮包的线程Thread t1 = new Thread(myrunnable1);Thread t2 = new Thread(myrunnable1);//创建生产皮鞋的线程Thread t3 = new Thread(myrunnable2);//启动线程t1.start();t2.start();t3.start();}
}
//描述生产皮包的任务
class MyRunnable1 implements Runnable{@Overridepublic void run() {System.out.println("生产皮包,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
//描述生产皮鞋的任务
class MyRunnable2 implements Runnable{@Overridepublic void run() {System.out.println("生产皮鞋,金币+1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

🌾3、多线程编程的意义

        使用多线程编程主要是了充分利用CPU资源,提高程序的运行效率。

        🌰:现在我们分别对两个变量进行10亿次的自增,分别使用两种方式:串行和并行。观察一下它们之间的时间差异。理论上来讲,并行应该是串行时间的一半。接下来我们俩看一下实际上是不是这样~

 结论:从上可以看出并行时间确实小于串行时间,但并不是严格意义上的一半,这主要是因为每创建一个线程都是要消耗时间和资源的。同样的,我们将计算量变小一些,可以看到反而串行时间小于并行时间。因此我们要知道并不是所有的场景下使用多线程第一可以提升效率,具体是否需要使用多线程主要根据计算量来决定。


🌾4、线程的类与常用方法

 🌈 4.1 构造方法

       Thread类是JVM用来管理线程的一个类。

 🌈 4.2 Thread类的几个常见属性

(1) 获取线程名:Thread.currentThread().getName();

(2)是否后台线程:isDaemon()

        isDaemon() 默认为false(前台线程),如果要创建后台线程则传入true,手动设置为后台线程。其中在main方法结束之后,线程会自动结束。

❓ 问题:前台线程与后台线程的区别?

        应用程度的主线程以及使用new Thread方式构造的线程都默认是前台线程。通过BeginXXX方法运行的线程都是后台线程,托管线程池中的线程都是后台线程。

        前台线程与后台线程的主要区别就是:进程会等待所有的前台线程完成后再结束工作,但是如果只剩下后台线程,则会直接结束工作。如果程序定义了一个不会完成的前台线程,主程序不会正常结束。

       比如银行转账的业务,一定要用前台线程;统计微信步数这种处理容错率比较高的业务或者辅助功能等,就可以使用后台线程。

后台线程演示: 

     public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});//第一次:在线程启动之前 设置线程为后台,观察线程的存活状态thread.setDaemon(true);System.out.println("在线程start之前设置为后台线程,此时的存活状态是:"+ thread.isAlive());//启动线程thread.start();//此时休眠是因为start之后,系统要去创建PCB,给系统一点时间能够创建成功Thread.sleep(2000);//第二次:在start线程之后,观察线程的存活状态System.out.println("在线程start之后观察线程的存活状态:"+thread.isAlive());System.out.println("main线程执行完成");System.out.println("此时线程是否存活:"+thread.isAlive());}

(3)是否存活 isAlive()指的是系统的线程PCB是否存活,并不是说我们new出来的Thread对象。

(4)是否被中断:停止或者终止当前现成的任务

        方式1:通过设置中断标识:主要注意代码中的while(!isQuit) 和 isQuit = true这两点。

          方式2:通过调用Thread类提供的interruped()方法来中断线程。isInterrupted()默认为false不中断。

        注意看下面的写法:有两处改动,但是会抛出异常。

        这主要是因为上面的两处改动都针对的是runnable状态中的异常处理,所以我们还要对 Sleep状态做处理:在catch中处理:有三种方式:

(5)等待一个线程 join():等待线程结束

(6)获取当前线程引用:Thread thread = Thread.currentThread();

(7)start()方法

❓  问题:start()方法与run()方法的区别?(面试题)
        start():申请一个真正的系统线程

        run() :定义线程要执行的任务。

        直接调用run方法,并不会去申请一个真正的系统线程(PCB),只是一个普通的方法调用,是单独的调用对象的方法。调用start方法,JVM会调用本地方法去系统中真正的申请一个线程(PCB),并执行run方法中 的逻辑。


 🌾5、线程的状态

注意线程的状态指的是Thread对象(有自己的生命周期)的状态,并不是PCB的状态。主要有以下几种:

1、NEW :java对象创建好了,但是还没有调用start方法创建PCB。

2、RUNNABLE : 就绪和运行状态。可以随时调度到CPU中执行。

3、TERMINATED: 线程任务执行完成,PCB在操作系统中已经销毁,但是java对象还存在。 

4、TIMED_WATING :等待一段时间,这个时间是有时间限制的等待(过时不候)。比如sleep(),常见的访问超时。

5、WAITING:没有时间限制的等待。

6、BLOCK:等待锁的时候进入的阻塞状态。

        最后,知道 在系统中针对线程的两个调度是用两个队列来实现的。准备执行的线程在就绪队列中,随时等待CPU调度。当调用sleep,wait,join方法时,就会被移动到阻塞队列中。当休眠时间到了之后,就会被移动回就绪队列,重新参与CPU调度。


相关文章:

【JavaEE初阶】认识线程(Thread)

目录 🌾 前言 🌾 了解线程 🌈1.1 线程是什么? 🌈1.2 一些基本问题 🌾2、创建线程的方式 🌈 2.1 继承Thread类 🌈 2.2 实现Runnable接口并重写run()方法 🌈 注意…...

自动化运维工具一Ansible Roles实战

目录 一、Ansible Roles概述 1.1.roles官方的目录结构 1.2.Ansible Roles依赖关系 二、Ansible Roles案例实战 2.1.Ansible Roles NFS服务 2.2 Roles Memcached 2.3 Roles-rsync服务 一、Ansible Roles概述 之前介绍了 Playbook 的使用方法,对于批量任务的部…...

json 中有递归parentId节点转 c#实体类时如何处理

如果您有一个具有递归parentId节点的JSON数据,并且您需要将其转换为C#实体类,则可以使用以下方法: 创建一个类来表示JSON对象的节点,包括它的属性和子节点。 public class Node {public int Id { get; set; }public string Name …...

给大家介绍几个手机冷门但好用的小技巧

技巧一:拍照识别植物 手机的拍照识别植物功能是指在使用手机相机时,可以通过对植物进行拍照,并通过植物识别技术,获取植物的相关信息和资料。其主要优点如下: 方便实用:使用拍照识别植物功能,…...

2.3 定点乘法运算

学习目标: 如果我要学习定点乘法运算,我会按照以下步骤进行学习: 确定学习目标:明确学习定点乘法运算的目的和重点,以便有针对性地进行学习。 掌握基础知识:首先需要了解定点数和定点乘法的基础知识&…...

C++每日一练:打家劫室(详解动态规划法)

文章目录 前言一、题目二、分析三、代码总结 前言 这题目出得很有意思哈,打劫也是很有技术含量滴!不会点算法打劫这么粗暴的工作都干不好。 提示:以下是本篇文章正文内容,下面案例可供参考 一、题目 题目名称: 打家…...

Wireshark使用

Capture Filters 语法 <Protocol name><Direction><Hosts><Value><Logical operations><Expressions> e.g 1.tcp src port 443 只抓取来源端口是443的tcp数据 2.not arp 不获取arp数据 3.port 80 获取端口是80的数据&#xff0c;不指…...

这才是 SpringBoot 统一登录鉴权、异常处理、数据格式 的正确姿势

本篇将要学习 Spring Boot 统一功能处理模块&#xff0c;这也是 AOP 的实战环节 用户登录权限的校验实现接口 HandlerInterceptor WebMvcConfigurer 异常处理使用注解 RestControllerAdvice ExceptionHandler 数据格式返回使用注解 ControllerAdvice 并且实现接口 Response…...

Java面试题总结 | Java面试题总结6-MYSQL模块(持续更新)

Mysql 文章目录 Mysql关系型数据库和非关系型数据库的区别什么是ORM?-**mybatis**如何评估一个索引创建的是否合理&#xff1f;Count函数执行效果上&#xff1a;执行效率上&#xff1a;count(主键)和count(列名) 数据库的三大范式Mysql中char和varchar的区别数据库设计或者功能…...

Linux命令集(Linux文件管理命令--mv指令篇)

Linux命令集&#xff08;Linux文件管理命令--mv指令篇&#xff09; Linux文件管理命令集&#xff08;mv指令篇&#xff09;2. mv(move)1. 文件移动2. 递归移动目录3. 文件目录重命名4. 强制移动5. 备份覆盖的目标文件6. 试探性移动7. 显示移动进度8. 补集操作9. 修改文件的权限…...

不一样的 Git 之间 | GitLab vs GitHub vs Gitee vs GitCode

Git仓库对比&#xff1a;GitLab vs GitHub vs Gitee vs GitCode 在软件开发中&#xff0c;版本控制是必不可少的工具之一。Git作为目前最为流行的版本控制系统&#xff0c;也逐渐成为了开发者们的标配。但是&#xff0c;如何选择一个合适的Git仓库来存储您的代码呢&#xff1f;…...

海尔牵头IEEE P2786国际标准通过Sponsor投票并连任工作组主席

01 海尔牵头IEEE P2786国际标准 通过Sponsor投票 并连任工作组主席 海尔牵头制定的全球首个服装物联网国际标准IEEE P2786《Standard for General Requirements and Interoperability for Internet of Clothing》通过Sponsor投票&#xff0c;标志着该国际标准草案得到了行业…...

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析

倾斜摄影超大场景的三维模型的顶层合并的纹理压缩与抽稀处理技术分析 倾斜摄影超大场景的三维模型的顶层合并需要对纹理进行压缩和抽稀处理&#xff0c;以减小数据量和提高数据的传输和展示性能。以下是一种常用的纹理压缩和抽稀处理技术&#xff1a; 1、纹理图集 纹理瓦片化…...

linux命令之iostat详解

iostat 监视系统输入输出设备和CPU的使用情况 推荐Linux命令在线工具&#xff1a;linux在线查询工具 补充说明 iostat命令 被用于监视系统输入输出设备和CPU的使用情况。它的特点是汇报磁盘活动统计情况&#xff0c;同时也会汇报出CPU使用情况。同vmstat一样&#xff0c;ios…...

【C++】程序员必备知识:认识类与对象

【C】程序员必备知识&#xff1a;认识类与对象 ①.面向过程和面向对象②.类的引入③.类的定义Ⅰ.定义方式Ⅱ.命名规则建议&#xff1a; ④.类的访问限定符及封装Ⅰ.访问限定符Ⅱ.封装 ⑤.类的作用域⑥.类的实例化⑦.类的对象大小计算Ⅰ.如何计算&#xff1f;Ⅱ.类对象存储方式Ⅲ…...

python基础实战5-python基本结构

1 if语句 if语句是用来进行判断的&#xff0c;其使用格式如下 if 要判断的条件&#xff1a; 条件成立时&#xff0c;要做的事情 案例一&#xff1a; age 30 print("------if判断开始------") if age > 18:print("我成年了") print("------if判断…...

移动端异构运算技术 - GPU OpenCL 编程(基础篇)

一、前言 随着移动端芯片性能的不断提升&#xff0c;在移动端上实时进行计算机图形学、深度学习模型推理等计算密集型任务不再是一个奢望。在移动端设备上&#xff0c;GPU 凭借其优秀的浮点运算性能&#xff0c;以及良好的 API 兼容性&#xff0c;成为移动端异构计算中非常重要…...

QString类方法和变量简介(全)

QString类方法和变量简介 操作字符串(|append|insert|sprintf|QString::arg()|prepend|replace|trimmed|simplified)查询字符串(startsWith|endsWith|contains|localeAwareCompare|compare)字符串转换 标准C提供了两种字符串&#xff1a;一种是C语言风格的以"\0"字符…...

中移链控制台对接4A平台功能验证介绍

中移链控制台具备单独的注册登录页面&#xff0c;用户可通过页面注册或者用户管理功能模块进行添加用户&#xff0c;通过个人中心功能模块进行用户信息的修改和密码修改等操作&#xff0c;因业务要求&#xff0c;需要对中移链控制台的用户账号进行集中管理&#xff0c;统一由 4…...

必知的Facebook广告兴趣定位技巧,更准确地找到目标受众

在Facebook广告投放中&#xff0c;兴趣定位是非常重要的一环。兴趣定位不仅可以帮助我们找到我们想要的目标受众&#xff0c;还可以帮助我们避免一些常见的坑。今天&#xff0c;就让我们一起来看看必知的Facebook广告兴趣定位技巧&#xff0c;更准确地找到目标受众。 1.不要只关…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...