第十章 进程间的通信 之 多线程基础(一)

文章目录

  • (一)多线程基础知识
    • 1、线程
      • (1)定义
      • (2)作用
      • (3)状态及状态转换
      • (4)分类
      • (5)优先级
    • 2、多线程
      • 2.1)定义
      • 2.2)Android多线程编程两大原则
      • 2.3)实现方式
      • 2.4)线程调度
      • 2.5)线程同步
      • 2.6)线程联合
    • 3、进程
      • 3.1)定义
      • 3.2)作用
      • 3.3)状态及状态转换
      • 3.4)线程与进程区别

(一)多线程基础知识

1、线程

(1)定义

一个基本的CPU执行单元 & 程序执行流的最小单元,比进程更小的可独立运行的基本单位,可理解为:轻量级进程
组成:线程ID + 程序计数器 + 寄存器集合 + 堆栈
注:线程自己不拥有系统资源,与其他线程共享进程所拥有的全部资源。

(2)作用

减少程序在并发执行时所付出的时空开销,提高操作系统的并发性能。
为什么有了线程还要有进程?
进程的缺陷:

  1. 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
  2. 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。

进程属于在处理器这一层上提供的抽象;线程则属于在进程这个层次上再提供了一层并发的抽象。线程用于提高进程的并发度。
进程和线程的主要差别在于它们是不同的操作系统资源管理方式:
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体, 是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

(3)状态及状态转换

第十章 进程间的通信 之 多线程基础(一)_第1张图片

(4)分类

4.1)守护线程
守护用户线程的线程,即在程序运行时为其他线程提供一种通用服务,如垃圾回收线程

//设置该线程为守护线程
thread.setDaemon(true);

4.2)非守护线程(用户线程)
a.主线程(UI线程)
Android系统在程序启动时会自动启动一条主线程,用于处理四大组件与用户进行交互的事情(如UI、界面交互相关)
注:因为用户随时会与界面发生交互,因此主线程任何时候都必须保持很高的响应速度,所以主线程不允许进行耗时操作,否则会出现ANR
b.子线程(工作线程)
用户手动创建的线程,用于处理耗时的操作(网络请求、I/O操作等)
4.3)守护线程 & 非守护线程的区别
区别:虚拟机是否已退出:
当所有用户线程结束时,因为没有守护的必要,所以守护线程也会终止,虚拟机也同样退出;反过来,只要任何用户线程还在运行,守护线程就不会终止,虚拟机就不会退出。守护线程不属于不可或缺的存在。

(5)优先级

5.1)表示
线程优先级分为10个级别,分别用Thread类常量表示。

Thread.MIN_PRIORITY // 优先级1
Thread.MAX_PRIORITY // 优先级10

5.2)设置
通过方法setPriority(int grade)进行优先级设置
默认线程优先级是5,即 Thread.NORM_PRIORITY

2、多线程

2.1)定义

多线程
一个程序(进程)运行时产生多个线程(任务)同时进行。
多线程目的
提高CPU资源的利用率,包括以下三点:

  1. 避免阻塞(异步调用)
    单个线程中的程序,是顺序执行的。如果前面的操作发生了阻塞,那么就会影响到后面的操作。
  2. 避免CPU空转
    如果服务器只用单线程,即处理完一条HTTP请求,再处理下一条请求的话,CPU会存在大量的闲置时间。因为处理一条请求,经常涉及到RPC、数据库访问、磁盘IO等操作,这些操作的速度比CPU慢很多,而在等待这些响应的时候,CPU却不能去处理新的请求,其余的请求只能一直处于等待状态,因此服务器的性能就很差
  3. 提升性能
    多线程可以同时执行多个任务,对于可并发执行的任务而言,确实提高了性能。

并行与并发
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。
其实,多线程本质是并发执行程序。因为计算机任何特定时刻只能执行一个任务;多线程只是一种错觉:只是因为JVM快速调度资源来轮换线程,使得线程不断轮流执行,所以看起来好像在同时执行多个任务而已(异步执行)
线程安全
一段代码是线程安全的是指:在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:

void transferMoney(User from, User to, float amount){
    to.setMoney(to.getBalance() + amount);
    from.setMoney(from.getBalance() - amount);
}

如果线程不安全,则程序执行的结果并不是我们想要的结果,甚至有可能会导致实际场景严重的安全问题。
同步与异步
同步:发送一个请求,等待返回,然后再发送下一个请求;同步可以避免出现死锁,读脏数据的发生,可以保证安全性。
异步:发送一个请求,不等待返回,随时可以再发送下一个请求;异步则是可以提高效率,可以并发执行多项工作。
Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。

2.2)Android多线程编程两大原则

(1)多线程编程两大原则
1、不要阻塞UI线程(即主线程):单线程会导致主线程阻塞,然后出现ANR错误:主线程被阻塞超过5s则会出现错误
2、不要在UI线程之外更新UI组件
(2)解决方案——1个主线程+n个工作线程
1、将耗时任务放在工作线程中执行
2、将更新UI组件放在主线程中执行

2.3)实现方式

第十章 进程间的通信 之 多线程基础(一)_第2张图片

2.4)线程调度

(1)调度方式
1、当系统存在大量线程时,系统会通过时间片轮转的方式调度线程,因此线程不可能做到绝对的并发
2、处于就绪状态(Runnable)的线程都会进入到线程队列中等待CPU资源(同一时刻在线程队列中可能有很多个)
3、在采用时间片的系统中,每个线程都有机会获得CPU的资源以便进行自身的线程操作;当线程使用CPU资源的时间到后,即时线程没有完成自己的全部操作,JVM也会中断当前线程的执行,把CPU资源的使用权切换给下一个队列中等待的线程。(被中断的线程将等待CPU资源的下一次轮回,然后从中断处继续执行)
(2)调度优先级
Java虚拟机(JVM)中的线程调度器负责管理线程,并根据以下规则进行调度:
1、根据线程优先级(高-低),将CPU资源分配给各线程
2、具备相同优先级的线程以轮流的方式获取CPU资源

2.5)线程同步

1、定义
当线程A使用同步方法A时,其他线程必须等到线程A使用完同步方法A后才能使用
2、同步方法用关键字 Synchronized 进行修饰

public synchronized void Sb_Android(){
        }

3、死锁
(3.1)死锁的四个必要条件

  • 互斥:每个资源要么已经分配给了一个进程,要么就是可用的。
  • 占有和等待:已经得到了某个资源的进程可以再请求新的资源。
  • 不可抢占:已经分配给一个进程的资源不能强制性地被抢占,它只能被占有它的进程显式地释放。
  • 环路等待:有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程所占有的资源。

(3.2)死锁的处理方法

  • 鸵鸟策略
  • 死锁检测与死锁恢复
  • 死锁预防
  • 死锁避免

(3.3)鸵鸟策略
把头埋在沙子里,假装根本没发生问题。
因为解决死锁问题的代价很高,因此鸵鸟策略这种不采取任务措施的方案会获得更高的性能。当发生死锁时不会对用户造成多大影响,或发生死锁的概率很低,可以采用鸵鸟策略。
大多数操作系统,包括 Unix,Linux 和 Windows,处理死锁问题的办法仅仅是忽略它。
(3.4)死锁的检测与死锁恢复

  1. 死锁的检测——资源分配图
    每种类型一个资源的死锁检测算法是通过检测有向图是否存在环来实现,从一个节点出发进行深度优先搜索,对访问过的节点进行标记,如果访问了已经标记的节点,就表示有向图存在环,也就是检测到死锁的发生。
  2. 死锁的恢复
  • 利用抢占恢复
  • 利用回滚恢复
  • 通过杀死进程恢复

(3.5)死锁的预防
在程序运行之前预防发生死锁。

  1. 破坏互斥条件
    例如假脱机打印机技术允许若干个进程同时输出,唯一真正请求物理打印机的进程是打印机守护进程。
  2. 破坏占有和等待条件
    一种实现方式是规定所有进程在开始执行前请求所需要的全部资源。
  3. 破坏不可抢占条件
  4. 破坏环路等待
    给资源统一编号,进程只能按编号顺序来请求资源。

(3.6)死锁的避免

  1. 安全状态
    如果没有死锁发生,并且即使所有进程突然请求对资源的最大需求,也仍然存在某种调度次序能够使得每一个进程运行完毕,则称该状态是安全的。
  2. 银行家算法
    算法要做的是判断对请求的满足是否会进入不安全状态,如果是,就拒绝请求;否则予以分配。

2.6)线程联合

线程A在占有CPU资源期间,通过调用join()方法中断自身线程执行,然后运行联合它的线程B,直到线程B执行完毕后线程A再重新排队等待CPU资源,这个过程称为线程A联合线程B

3、进程

3.1)定义

是进程实体的运行过程 & 系统进行资源分配和调度的一个独立单位

3.2)作用

使多个程序可 并发执行,以提高系统的资源利用率和吞吐量

3.3)状态及状态转换

第十章 进程间的通信 之 多线程基础(一)_第3张图片
第十章 进程间的通信 之 多线程基础(一)_第4张图片

3.4)线程与进程区别

第十章 进程间的通信 之 多线程基础(一)_第5张图片

你可能感兴趣的:(Android学习之旅,Android)