前言
实践是最好的学习方式,技术也如此。
一、软件与操作系统
-
软件
- 定义: 软件是程序的载体,写的代码,打包出来就是软件,就能安装在各种设备上,然后运行在操作系统上。(程序就是用于指导计算机的一系列抽象指令,而软件是程序实际编译运行在计算机上而存在的产品。软件是程序的一种载体和实现形式。两者关系就像设计和产品、理论和实践)
- 分类:系统软件(操作系统),应用软件(都要运行在操作系统上);
-
操作系统
- 作用
- 1)负责跟系统硬件打交道,把用户的各种操作(比如鼠标点击、键盘输入等)翻译给计算机硬件,然后将结果告诉用户;
- 2)管理其他软件;
- 管理其他软件
- 操作系统如何管理其它软件:通过管理进程;
- 作用
二、进程与线程
-
软件是程序的载体,每个程序都是一个进程;
-
每个程序都有一个进程,线程是进程的一部分,线程是操作系统能调度的最小单元;
-
通俗例子解释
- 背景:村庄
- 村长:操作系统; 管理每个家庭;单独指挥一个人去做事(一个线程);
- 一个软件就是一个家庭,这个家庭就是一个进程;
- 一个家庭是一个进程,家中有我、父亲、母亲(每个人都是一个线程);
- 背景:村庄
-
线程的优点
- 使用线程可以提高程序的运行速度,节省时间和成本;
- 变串行为并行,提高速度,节省时间;
- 串行:一件事同一时刻只有一个人做;
- 并行:一件事同一时刻有多个人做;
-
多线程资源冲突:多个线程在同一时刻操作同一个资源;
- 操作资源:对资源进行了修改;
// 定义资源i int i = 10; // 访问资源,没有修改i println(i); // 操作资源,对i进行了修改 i = 1;
- 操作资源:对资源进行了修改;
-
线程是进程的一部分,是操作系统调度的最小单位(是调度的最小单位,不是持有资源的最小单位);
-
资源都是在进程中的,进程是持有资源的最小单位;线程可以使用资源,但是不能持有资源;
-
每一个进程都有一块内存,这个内存是所有线程共享的。每一个线程都有一个缓存,这个缓存是自己独占的;
-
例如,进程 p,进程 p 有个线程 a,线程 a 的执行逻辑
- CPU 将 a 需要的数据从进程 P 的内存读入线程 a 的缓存;如 i;
- a 对自己缓存的数据进行操作;如 i ++;
- a 执行完毕,cpu 将 a 缓存的数据 i 写回到进程 p 的内存中;
-
资源冲突:多个线程在同一时刻操作同一个资源;同一时刻,同一目标;
线程 a 执行的同时,进程 p 中 的另一个线程 b 也在执行,且也用到了 P 内存中的 i;那么,线程 b 执行完成后,i 是多少呢,是以线程 a 执行的为准,还是线程 b 执行的为准; -
解决资源冲突:不同时或不同目标(破坏同一时间或同一目标这两个条件)
- 不同时:排队,变并行为串行;在 i 被读入线程 a 的内存中时,加个标记;其它线程来看到这个标记会等着,等到线程 a 执行完成将 i 写回到内存中时,再把标记清除我,并通知其他线程,其他线程再开始执行。
1、进程
- 进程(Process)是操作系统分配资源的基本单位,它是一个执行中的程序实例;
- 每个进程都有自己独立的内存空间,不同进程的内存是相互独立的;
- 在Android系统中,每个应用都会以一个新的进程运行,系统会自动帮我们管理这些进程;
- 默认情况下,Android系统会为每个App分配一个进程。这个默认进程里可以包含多个Activity);
- 当在这个进程内启动一个新的Activity时,是直接在该进程create一个Activity实例,不会创建新进程;
- 多个Activity会共享该应用进程的资源和内存空间;
- 单纯启动新Activity并不会造成进程切换,对系统资源影响较小
2、线程
* 线程就是让==一个程序==有能力==同时完成多件事情==;
- 线程是正在运行的程序中的一条独立的执行路径;
- 主线程
- 当 Android 程序启动时,系统会创建一个主线程,也称为 UI 线程;
- UI 线程是应用程序与 Android UI 工具包中的组件交互的方式(在这个线程中可以更新UI,处理用户输入事件等。UI组件像Activity、View都是在UI线程中初始化和创建的。);
- UI线程负责处理用户界面的创建、更新和响应用户交互事件,确保应用的用户界面保持流畅、响应迅速,并提供良好的用户体验
- UI 线程只能处理和界面相关的工作,比如绘制界面,处理点击事件等,区分UI线程和工作线程,就是让耗时操作不阻塞界面,以保证应用的流畅性和用户体验;
- 后台(工作)线程是除主线程或 UI 线程之外的任何线程;
- AsyncTask:
- 来简化这种需要后台工作的场景;
- 可以把AsyncTask看成一个工人,我们在主线程中告诉它需要做什么工作,它会自己另开一个线程(后台线程)去工作。工作完成后它再回到主线程,通过回调方法将结果返回给我们。这样下来,我们的主线程(UI线程)就可以专注于更新界面,不会被阻塞。而AsyncTask也封装了线程管理和线程间通信的复杂性,我们只需要告诉它做什么工作就可以了;
- AsyncTask 通过异步线程可以避免阻塞,回调机制又可以获取结果;
三、实现
- 回调:至于回调的概念,它表示一种函数或方法,当特定事件发生时就会被执行。回调不会主动调用,而是在满足条件时由别处调用以完成响应。在Android中,回调机制很常见,例如点击事件的onClick()就是一个回调方法。
AsyncTask通过线程间的回调,很好地结合了后台工作与UI更新,极大地方便了程序逻辑的管理。
- TextView、Button;
- 用户单击 Button 时,应用程序会休眠一段随机时间,然后在唤醒时在 TextView 中显示一条消息;
// 第一个泛型参数String: 表示异步任务输入参数的类型:String
// 第二个泛型参数Integer: 表示后台任务执行进度的类型:Integer
// 第三个泛型参数Bitmap: 表示异步任务最终返回结果的类型:
// 知识点:<T>表示类型参数T,用于在定义Box类时传入实际的类型
public class MyAsyncTask
extends AsyncTask <String, Integer, Bitmap>{}
应用现在有一个在后台执行工作的 AsyncTask 类,现在可以为“启动任务”按钮实现 onClick 方法来触发后台任务;
doInBackground():实现代码以执行要在单独线程上执行的工作
onPostExecute():在doInBackground()执行结束后,自动在UI线程被调用,并接收doInBackground()的返回值。函数参数就是从doInBackground()中返回的结果
四、异步任务加载器
EditText,Button,TextView
需求:用户在 EditText 中输入书名并点击按钮,查询用户正在查找的图书的作者和书名,结果显示在 TextView 中
五、解决并发
- 并发
- 定义:指同一个时间段,程序中有多个代码片段同时运行或交替运行的情况;
- 解决并发的基本操作
- 核心:破坏同一时刻或同一目标;
- 破坏同一时间的核心:排队;
- 加锁:在变量
a
被一个线程读取后,就加一个锁,如果被写回来,就释放锁,其他线程过来后发现有锁,就等着;实现同时只有一个线程使用变量a
; - 类比酒店入住,客人得到钥匙,并且锁门,这样别人就进不去了;离开再交还钥匙,下一个人就能入住了;即排队;
- 加了锁之后,原来的并行(多个线程一起执行),变成了串行(线程排队执行)