Android 线程基础 一 进程和线程及线程的状态

tech2024-04-10  60

线程基础 一

​ android沿用了Java的线程模型,一个Android应用在创建的时候会开启一个线程,即主线程(UI线程),其余的耗时活动(访问网络数据,计算,访问数据库)必须在子线程中完成,因为Android 3.0 以后,强制要求,否则会抛出异常,这是为了避免主线程被耗时操作阻塞导致ANR。(主线程被阻塞5s就ANR)

进程与线程

一、进程
​ 进程是操作系统结构的基础,是程序在一个数据集合上运行的过程,是系统进行资源分配和调度的基本单位。​ 进程就是程序的实体,同样,它也是线程的容器。​ 操作系统管理的基本运行单元。
二、线程
​ 操作系统调度的最小单元,也叫做轻量级进程。​ 进程中的一个执行任务(控制单元),负责当前进程中程序的之下。​ 一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可以共享数据。
三、两者区别
​ 根本区别:进程是操作系统资源分配的基本单位,线程是处理器任务调度和执行的基本单位。​ **资源开销:**每个进程都有独立的代码和数据空间(每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵),程序之间的也切换会有较大的开销; 同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。​ **包含关系:**如果一个进程内有多个线程,则执行过程不是一条线,而是多条线(线程)共同完成的;线程是进程的一部分。​ 内存分配:系统在运行的时候会为每个进程分配不同的内存空间,进程之间的地址空间和资源是相互独立的; 同一进程的线程共享本进程的地址空间和资源。​ **健壮性:**一个进程崩溃,在保护模式下不会对其他进程产生影响,一个线程崩溃,整个进程都死掉,多进程比多线程健壮。​ **执行过程:**线程必须依靠进程才能存在,两者都可以并发执行。

四、进程和线程的资源

堆栈

堆:

共有空间,是进程中最大的一块内存,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。对在操作系统对进程初始化的时候分配,运行过程中也可以向系统要额外的堆,但是如果不释放堆,会造成内存泄漏。主要用于存放新创建的对象。

每个线程独有,分为虚拟机栈和本地方法栈,分别对应java和native部分,保存其运行状态和局部自动变量的。栈在线程开始的时候初始化,每个线程的栈相互独立,因此栈是线程安全的。操作系统在切换线程的时候会自动切换栈。栈空间不用在高级语言显式的分配和释放。

程序计数器

每个线程独有的,为了保证线程切换以后能恢复到正确的执行位置。

字节码解释器通过程序计数器来依次读取指令,从而实现代码的流程控制,在多线程的情况下,程序计数器用于记录当前线程的执行位置,从而当当前线程被切换回来的时候能知道该线程上次执行到哪里了。

方法区

共有空间,主要存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

多线程

使用多线程的好处

在操作系统级别上来看,主要是以下几个方面:

**更快的响应程序:**使用多线程可以减少程序的响应时间。如果某个线程很耗时,或者陷入上时间的等待,此时程序将不会响应鼠标和键盘等的操作,使用多线程以后可以把这个耗时操作分配到一个单独的线程去执行,从而使程序具备了更好的交互性。**开销小,提高资源利用率:**与进程相比,线程的创建和切换开销更小,同时多线程在数据共享方面效率十分高。**提高CPU利用率:**多CPU或者多个计算机本身就具有多线程的能力。如果使用单线程,将无法重复利用计算机资源,这会造成资源的巨大浪费。在多CPU计算机中使用多线程能提高CPU的利用率。简单的程序设计使用多线程能简化程序的结构,使程序便于理解和维护。**优化性能:**使用多线程可以设置优先级以优化性能。

使用多线程的难点

等候使用共享资源时造成程序的运行速度变慢。这些共享资源主要是独占性的资源,如打印机。对线程进行额外管理要求额外的CPU开销。线程的使用会给系统带来上下文切换的额外负担。当这种负担超过一定限度,多线程的就得不偿失了。线程的死锁。不仅仅是死锁,主要是较长的等待或者资源竞争以及死锁等多线程现象。原子性的保持。因为多线程数据共享的特点,这是一个优点,同时也是一个难点,主要就是保证数据的原子性,不能出现脏读。

线程的状态

​ 可以直接查看源码:

public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }

分为六个状态:

NEW: 新创建状态。线程被创建,但是还么有调用start方法,在线程运行之前还有一些基础工作要做。NEW这种状态对于每个线程来说,只可能有一次处于该状态,因为线程实例只能被启动一次。**Runnable:**可运行状态。一旦调用start方法,线程就处于runnable状态。一个可运行的线程可能处于运行状态,也可能没有运行,这取决于操作系统的调度。**Blocked:**阻塞状态。当线程申请一个由其他线程持有的独占资源(比如锁)时就会处于该状态。当线程不再阻塞时,状态会从BLOCKED转为RUNNABLE。Waiting:等待状态。线程暂时不活动,并且不运行任何代码,这是消耗最少的状态,等待线程调度器重新激活他。**Timed waiting:**超市等待激活。和等待状态不同的是,它可以在指定时间结束以后自行返回。**Terminated:**终止状态。当前线程执行完毕。无论是正常run方法执行完毕还是异常终止,都终止了。
状态改变:

NEW到Runnable

Java刚创建出来的Thread对象就是NEW状态,不会被操作系统调度执行。从NEW到RUNNABLE状态调用start方法就行,这时候操作系统可以调度这个线程了。

Runnable到Blocked

是synchronized修饰的方法,代码同一时刻只允许一个线程持有,其余线程只能阻塞等待,等待的线程就会从Runnable到Blocked。

当等待的线程获得 synchronized 隐式锁时,就又会从 BLOCKED 转变到 RUNNABLE 状态。 在操作系统层面,线程是会转变到休眠状态的,但是在 JVM 层面,Java 线程的状态不会发生变化,即 Java 线程的状态会保持 RUNNABLE 状态。JVM 层面并不关心操作系统调度相关的状态,因为在 JVM 看来,等待 CPU 使用权(操作系统层面处于可执行状态)与等待 I/O(操作系统层面处于休眠状态)没有区别,都是在等待某个资源,都归入了 RUNNABLE 状态。

Runnable与Waiting的状态改变

获得 synchronized 隐式锁的线程,调用无参数的 Object.wait() 方法,状态会从 RUNNABLE 转变到 WAITING;调用 Object.notify()、Object.notifyAll() 方法,线程可能从 WAITING 转变到 RUNNABLE 状态。调用无参数的 Thread.join() 方法。join() 是一种线程同步方法,如有一线程对象 Thread t,当调用 t.join() 的时候,执行代码的线程的状态会从 RUNNABLE 转变到 WAITING,等待 thread t 执行完。当线程 t 执行完,等待它的线程会从 WAITING 状态转变到 RUNNABLE 状态。调用 LockSupport.park() 方法,线程的状态会从 RUNNABLE 转变到 WAITING;调用 LockSupport.unpark(Thread thread) 可唤醒目标线程,目标线程的状态又会从 WAITING 转变为 RUNNABLE 状态。

RUNNABLE 与 TIMED_WAITING 的状态转变

Thread.sleep(long millis)

Object.wait(long timeout)

Thread.join(long millis)

LockSupport.parkNanos(Object blocker, long deadline)

LockSupport.parkUntil(long deadline)

TIMED_WAITING 和 WAITING 状态的区别,仅仅是调用的是超时参数的方法。

RUNNABLE 到 TERMINATED 状态

线程执行完 run() 方法后,会自动转变到 TERMINATED 状态执行 run() 方法时异常抛出,也会导致线程终止Thread类的 stop() 方法已经不建议使用
最新回复(0)