【安卓笔记】进程和线程的基础知识

0. 环境:

电脑:Windows10

Android Studio: 2024.3.2

编程语言: Java

Gradle version:8.11.1

Compile Sdk Version:35

Java 版本:Java11

1. 先熟悉JVM虚拟机的线程

----------以下都是系统线程,由JVM管理,通常无需直接操作,仅需了解即可。----------

先创建一个Java module(创建方法可以看我这篇文章的3.1)

3.1 创建module

首先,创建一个module:菜单--file--new--new module...

注意左侧选择Java or Kotlin Library,右侧填写相应信息。点finish

 然后执行以下代码:

public static void main(String[] args) {// 虚拟机线程管理的接口ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();// 取得线程信息ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);for (ThreadInfo threadInfo : threadInfos) {String logInfo = String.format("[%s] + %s", threadInfo.getThreadId(), threadInfo.getThreadName());// 打印线程Id和线程名称System.out.println(logInfo);}
}

运行后看结果:

[1] + main
[9] + Reference Handler
[10] + Finalizer
[11] + Signal Dispatcher
[12] + Attach Listener
[19] + Notification Thread
[20] + Common-Cleaner
---线程名称------作用---
main主线程,程序入口
Reference Handler处理引用对象
Finalizer执行对象的finalize()方法
Signal Dispatcher处理操作系统信号
Attach Listener支持动态附加(Attach)到JVM
Notification Thread处理JMX(Java管理扩展)通知
Common-Cleaner替代Finalizer的轻量级清理线程(Java 9+引入)

(没有看到GC线程,是因为目前没有资源需要回收。当出现资源需要回收时,才会触发JVM的GC线程。此时才有GC线程来回收资源。也就是GC回收机制)

----------以上都是系统线程,由JVM管理,通常无需直接操作,仅需了解即可。----------

 2. 运行线程的方式

三种方式:

--名称--备注
Thread线程
Runable任务,需要通过thread来运行该任务
Callable有返回值的任务,需要通过futureTask来挂载

示例代码:

// 第一种方式:thread
private static class Thread1 extends Thread {@Overridepublic void run() {super.run();System.out.println("--- run thread1 ---");}
}
// 第二种方式:runnable
private static class Runnable2 implements Runnable {@Overridepublic void run() {System.out.println("--- run runnable2 ---");}
}
// 第三种方式:callable
private static class Callable3 implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println("--- run callable3 ---");return "[result]: run success";}
}

运行方式如下:

public static void main(String[] args) {// 方法一的线程可以通过start()方法直接运行Thread1 thread1 = new Thread1();thread1.start(); // 需要通过start()来启动线程。run()函数不是启动线程,只是函数调用// 方法二的任务,需要通过线程来执行Runnable2 runnable2 = new Runnable2();Thread thread = new Thread(runnable2);thread.start();// 方法三的有返回值的任务,需要挂载在FutureTask,再通过线程来执行Callable3 callable3 = new Callable3();// 将callable挂载在futureTask上FutureTask<String> futureTask = new FutureTask<>(callable3);// 通过线程来执行futureTask任务Thread callableThread = new Thread(futureTask);callableThread.start();// 此时我们可以获取callable的返回值try {System.out.println("callable return: " + futureTask.get());} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}
}

运行后,可以看到结果:

--- run thread1 ---
--- run runnable2 ---
--- run callable3 ---
callable return: [result]: run success

3. 停止线程的方式

1. stop()停止(不推荐!)

非常不推荐使用stop()来停止线程,过时了。该函数属于暴力停止,有一定的危险性。例如来不及释放、会产生碎片等问题。甚至会被其他程序员鄙视(开玩笑的)

你就想吧,你在KTV里唱歌,唱到一半被人切歌了。你是不是想给他一拳

2. interrupt()中断

优雅的停止线程的方式,应该是让run()函数执行完之后,不再执行。

interrupt()是中断信号的函数

private static class InterruptThread extends Thread {@Overridepublic void run() {super.run();String threadInfo = String.format("[%s] %s", Thread.currentThread().getId(), Thread.currentThread().getName());String isRunning = String.format("%s is Running", threadInfo);String isStopped = String.format("%s is Stopped", threadInfo);while (!isInterrupted()) { // 注意这里,需要增加 中断信号的判断System.out.println(isRunning);}System.out.println(isStopped);// -------------以下为错误示范---------------/**while (true) { // 如果判断条件为true时,即使调用了thread.interrupt(). 该线程也无法停止System.out.println(isRunning);}System.out.println(isStopped);*/}
}

执行代码方法如下:

InterruptThread thread = new InterruptThread();
thread.start(); // 开启线程
try {Thread.sleep(10);
} catch (InterruptedException e) {throw new RuntimeException(e);
}
thread.interrupt(); // 发起中断信号

运行后,可以看到结果:

[21] Thread-0 is Running
[21] Thread-0 is Running
·····
[21] Thread-0 is Running
[21] Thread-0 is Running
[21] Thread-0 is Stopped

 最后确实停止了。

中断后,没有重启的概念。只有线程启动、线程中断(也就是停止)。要想再次启动线程,需要再次使用线程启动。

注意:

如果在run()函数中使用了sleep(),会导致interrupt信号被清除。如果需要使用sleep()函数,需要在抛异常部分,再次发送一次interrupt(); 这样即可中断线程。

参考示例:

private static class Thread1 extends Thread {@Overridepublic void run() {super.run();try {System.out.println("--- run thread1 ---");Thread.sleep(1000);} catch (InterruptedException e) {interrupt(); // 再次发送中断信号e.printStackTrace();}}
}

扩展:

如果不是继承Thread,而是实现Runnable,需要怎么改呢?

请看代码:

private static class InterruptThread2 implements Runnable {@Overridepublic void run() {String threadInfo = String.format("[%s] %s", Thread.currentThread().getId(), Thread.currentThread().getName());String isRunning = String.format("%s is Running", threadInfo);String isStopped = String.format("%s is Stopped", threadInfo);// 通过Thread.currentThread(),来获取线程while (!Thread.currentThread().isInterrupted()) {System.out.println(isRunning);}System.out.println(isStopped);}
}

4. 补充一个join()函数

join()的意思是放弃当前线程的执行,并返回对应的线程。

如果不是用join()会导致线程之间随机执行,无法做到控制顺序。

应用场景:执行完线程1后,需要执行线程2,则可以对线程1执行join()函数,再对线程2执行start()函数。达到先执行线程1,再执行线程2,从而达到控制线程执行顺序的效果。

贴代码

private static class InterruptThread extends Thread {public InterruptThread(String s) {super(s);//传入线程名称,用于区分不同线程}@Overridepublic void run() {super.run();String threadInfo = String.format("[%s] %s", Thread.currentThread().getId(), Thread.currentThread().getName());for (int i = 0; i < 100; i++) {System.out.println(i + ";" + getName() + threadInfo);}}
}
//执行代码:
InterruptThread thread1 = new InterruptThread("A");
InterruptThread thread2 = new InterruptThread("B");
thread1.start();
// thread1.join();//注意这个join。可以做到先执行thread1
thread2.start();

执行后看结果:

0;B[22] B
1;B[22] B
2;B[22] B
3;B[22] B
4;B[22] B
5;B[22] B
6;B[22] B
0;A[21] A
7;B[22] B
1;A[21] A
8;B[22] B
9;B[22] B
10;B[22] B
11;B[22] B
12;B[22] B
13;B[22] B
14;B[22] B
15;B[22] B
2;A[21] A
16;B[22] B
3;A[21] A
17;B[22] B
4;A[21] A
18;B[22] B
···

可以看到线程A和线程B混在一起,无法做到先后执行。如果使用了thread1.join(); 再运行之后,就可以做到执行完线程A后,再开始执行线程B。 

运行结果:

0;A[21] A
1;A[21] A
2;A[21] A
3;A[21] A
4;A[21] A
···
97;A[21] A
98;A[21] A
99;A[21] A
// 可以看到,完全执行完线程A之后,才会执行线程B
0;B[22] B
1;B[22] B
2;B[22] B
3;B[22] B
4;B[22] B
···
97;B[22] B
98;B[22] B
99;B[22] B

 5. sleep()和wait()的区别

sleepwait
是休眠是等待
可以无条件休眠

特殊原因需要等待

(例如:资源不足)

休眠需要带参: 休眠时间调用不用带参
休眠结束后,立刻有执行权需要手动唤醒,才有执行权
sleepwait
是休眠是等待
可以无条件休眠

特殊原因需要等待

(例如:资源不足)

休眠需要带参: 休眠时间调用不用带参
休眠结束后,立刻有执行权需要手动唤醒,才有执行权
会清除interrupt信号

 执行权并不代表马上执行。什么时候执行 取决于操作系统的调度。

写在最后

至此,我们就学会了线程的启动和停止。顺便学会了顺序执行线程。

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

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

相关文章

26-计组-多处理器

多处理器的基本概念1. 计算机体系结构分类依据&#xff1a;根据指令流和数据流的数量关系&#xff0c;计算机体系结构可分为四种类型&#xff1a;SISD、SIMD、MISD、MIMD。&#xff08;1&#xff09;SISD 单指令流单数据流定义&#xff1a;任意时刻计算机只能执行单一指令操作单…

vscode 插件开发activityba

在 VS Code 插件开发中&#xff0c;**Activity Bar&#xff08;活动栏&#xff09;**是左侧垂直导航栏的核心组成部分&#xff0c;它为用户提供了快速访问插件功能的入口。通过自定义 Activity Bar&#xff0c;开发者可以显著提升插件的可见性和用户体验。以下是关于 Activity …

【橘子分布式】Thrift RPC(理论篇)

一、简介 首先还是那句话&#xff0c;概念网上已经很多了&#xff0c;我们就不多逼逼了。我来大致介绍一下。 Thrift是一个RPC框架可以进行异构系统(服务的提供者 和 服务的调用者 不同编程语言开发系统)的RPC调用为什么在当前的系统开发中&#xff0c;会存在着异构系统的RPC…

项目进度依赖纸面计划,如何提升计划动态调整能力

项目进度依赖纸面计划会导致实际执行中的调整能力不足。提升计划动态调整能力的方法包括&#xff1a;建立动态进度管理系统、强化团队沟通与协作、定期开展风险评估与进度复盘。特别是建立动态进度管理系统&#xff0c;通过信息技术工具实现实时跟踪和反馈&#xff0c;使计划能…

递推预处理floor(log_2{n})

在C中&#xff0c;除了使用<cmath>中的log或log2函数求对数&#xff0c;也可以通过递推求出所有可能用到的⌊log⁡2i⌋,i∈[1,n]\lfloor \log_2i\rfloor, i\in[1, n]⌊log2​i⌋,i∈[1,n] 证明&#xff1a;⌊log⁡2i⌋⌊log⁡2⌊i2⌋⌋1\lfloor \log_2i \rfloor\lfloor \…

【AI智能体】智能音视频-搭建可视化智能体

可视化智能体是语音小伴侣智能体的升级版&#xff0c;支持语音与视频的双模态交互。本文详细介绍了音视频交互的实现原理、智能体搭建方法及效果测试&#xff0c;帮助开发者快速构建支持音视频交互的智能体。 应用场景 可视化智能体适用于多种场景&#xff0c;举例如下&#…

Sensoglove推出新一代外骨骼力反馈手套:主动力反馈+亚毫米级手指追踪,助力机器人操控与虚拟仿真

在工业自动化、虚拟现实和医疗康复等领域&#xff0c;高精度手部交互设备的需求日益增长。Sensoglove推出的Rembrandt外骨骼力反馈手套&#xff0c;结合主动力反馈、触觉反馈与亚毫米级追踪技术&#xff0c;为用户提供更自然、更安全的操作体验。Sensoglove外骨骼力反馈手套核心…

AutoMapper入门

在 ASP.NET Core 开发中&#xff0c;我们经常需要在不同层之间传递数据&#xff1a;比如从数据库模型&#xff08;Entity&#xff09;转换到 DTO&#xff0c;再从 DTO 转换为前端视图模型。这些转换代码大量重复、冗长、容易出错。为了解决这个问题&#xff0c;AutoMapper 诞生…

PyTorch武侠演义 第一卷:初入江湖 第1章:武林新秀遇Tensor - 张量基础

第一卷&#xff1a;初入江湖 第1章&#xff1a;武林新秀遇Tensor - 张量基础晨起码农村 鸡鸣三声&#xff0c;林小码已经收拾好了行囊。他最后看了眼床头那本翻旧的《Python入门心法》&#xff0c;轻轻抚平卷起的书角。 "小码&#xff0c;路上小心。"父亲将一把青铜匕…

Python进阶(4):类与面向对象程序设计

面向对象OOPOOP:Object Oriented Programming,面向对象编程,面向对象中的对象(Obiect)&#xff0c;通常是指客观世界中存在的对象&#xff0c;这个对象具有唯一性&#xff0c;对象之间各不相同&#xff0c;各有各的特点&#xff0c;每个对象都有自己的运动规律和内部状态;对象与…

如何在 Shopify 中创建退货标签

退货是电商运营中不可避免的一环&#xff0c;而一个顺畅、透明的退货流程&#xff0c;不仅能减少客户投诉&#xff0c;也有助于提升顾客对品牌的信任与忠诚度。Shopify 虽然没有内建退货标签自动生成功能&#xff0c;但通过合理设置与外部工具整合&#xff0c;你完全可以打造一…

I2C设备寄存器读取调试方法

1、查看I2C挂载设备 2、读取i2C设备所有寄存器 3、读取i2c设备的某个寄存器 4、向i2C设备某个寄存器写入一个值1、查看

K8S的Helm包管理器

一、背景 官网: https://helm.sh/ 我们针对K8S环境中&#xff0c;部署对应的应用&#xff0c;无外乎就是编写一堆yaml资源清单文件. 资源清单、依赖性少的时候&#xff0c;可以直接手动维护。但是&#xff0c;随着资源清单越来越复杂&#xff0c;越来越多&#xff0c;不同的环…

多模态数据处理新趋势:阿里云ODPS技术栈深度解析与未来展望

多模态数据处理新趋势&#xff1a;阿里云ODPS技术栈深度解析与未来展望 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 总有一行代码&#xff0c;能点亮万千星辰。 &#x1f50d; 在技术的宇宙中&#xff0c;我愿做永不停歇的探索者。 ✨ 用代码丈…

AI数据分析仪设计原理图:RapidIO信号接入 平板AI数据分析仪

AI数据分析仪设计原理图&#xff1a;RapidIO信号接入 平板AI数据分析仪 1 、概述 本仪器是一款面向工业控制、新能源、震动测量等业务开发的平板AI数据分析仪。基于 Jetson Orin Nano&#xff08;AI边缘计算&#xff09;、实现RapidIO接口数据接入&#xff0c;进行AI分析。Rap…

人工智能正逐步商品化,而“理解力”才是开发者的真正超能力

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

玩转ClaudeCode:ClaudeCode安装教程(Windows+Linux+MacOS)

Windows 环境安装 Claude Code 一、安装 WSL 环境 1. 确认 Windows 功能已开启 打开 “控制面板 → 程序 → 启用或关闭 Windows 功能” 勾选 “适用于 Linux 的 Windows 子系统” 和 “虚拟机平台” 点“确定”后重启电脑。 开机后&#xff0c;管理员模式打开 Terminal…

PyTorch多层感知机(MLP)模型构建与MNIST分类训练

冲冲冲&#x1f60a; here&#x1f60a; 文章目录PyTorch多层感知机模型构建与MNIST分类训练笔记&#x1f3af; 1. 任务概述⚙️ 2. 环境设置2.1 导入必要库2.2 GPU配置&#x1f9e0; 3. 模型构建3.1 模型定义关键点3.2 损失函数选择3.3 模型初始化与设备选择&#x1f527; 4. …

android tabLayout 切换fragment fragment生命周期

1、TabLayout 与 Fragment 结合使用的常见方式 通常会使用 FragmentPagerAdapter 或 FragmentStatePagerAdapter 与 ViewPager 配合,再将 TabLayout 与 ViewPager 关联,实现通过 TabLayout 切换 Fragment。 以下是布局文件示例 activity_main.xml: <LinearLayout xmln…

马蹄集 BD202401补给

可怕的战争发生了&#xff0c;小度作为后勤保障工作人员&#xff0c;也要为了保卫国家而努力。现在有 N(1≤N≤)个堡垒需要补给&#xff0c;然而总的预算 B(1≤B≤)是有限的。现在已知第 i 个堡垒需要价值 P(i) 的补给&#xff0c;并且需要 S(i) 的运费。 鉴于小度与供应商之间…