进程与线程
1.1 什么是进程?
是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是操作系统动态执行的基本单元。
通俗地讲一个进程代表一个应用程序,该应用程序运行在自己的进程当中,使用系统为其分配的堆内存,不受其他应用程序或者是其他进程的影响,是独立运行的。当然一个进程中可以同时运行多个应用程序,这时堆内存是共享的。
Android系统中,一个进程对应一个虚拟机,缺省情况下,一个应用的所有组件都运行在同一个进程中,当启动一个应用程序组件时,如果该应用没有正在运行的其它程序组件,那么Android系统将为这个应用创建一个新进程用于运行应用;在启动一个应用程序组件时,这个应用已经有进程在运行(因为有应用的其它组件存在),那么这个应用程序组件将使用同一进程运行;你可以使用不同进程来运行不同的组件,或者在进程中创建新的线程。
1.2 进程模型
基于用户ID的分配机制:
安装Android应用程序时,Android系统会为每个程序分配一个Linux用户ID,并设置相应的权限,这样其它应用程序就不能访问此应用程序所拥有的数据和资源。在Android系统上,一个用户ID识别一个应用程序。应用程序通常位于设备上的ROM中,其在安装时被分配一个用户ID,并且保持不变。默认情况下,每个Android应用程序运行在它自己的进程中。当需要执行应用程序时,Android会启动一个虚拟机,即一个新的进程来执行,因此不同的Android应用程序运行在相互隔离的环境中。
假如两个应用程序的用户ID是一样的,那么这两个应用程序将运行在同一个进程中,这就是一个进程中存在多个应用程序的情况,此时这两个应用程序使用同一份堆内存,使用同一个虚拟机。要实现这个功能,首先必须使用相同的私钥签署这些应用程序,然后必须使用AndroidManifest.xml文件给它们分配相同的 Linux用户ID,这通过在manifest节点下得属性android:shared UserId来实现。
1.3 Android中进程的生命周期
Android系统为每个应用程序分配了一个进程,应用程序中组件(Activity,Service,BroadCast)的状态决定的一个进程的“重要性层次”,层次最低的属于旧进程。这个“重要性层次”有五个等级,也就是进程的生命周期,按最高层次到最低层次排列如下:
前台进程 可见进程 服务进程 背景进程 空进程
1.3.1 前台进程:
进程被认为是前台进程需满足下面条件之一:
本进程中有Activity是当前和用户有交互的Activity;
本进程中有Service和当前用户有交互Activity的绑定;
本进程中有在前台运行的Service;
本进程中有Service正在执行某个生命周期回调函数;
本进程中的某个BroadcastReceiver正在执行onReceive()方法。
1.3.2 可见进程:
这种进程不含有任何在前台运行的组件,但会影响当前显示给用户屏幕上的内容。
进程被认为是可见进程需满足下面条件之一:
本进程含有一个虽然不在前台但却部分可见的Activity;
本进程含有绑定到可见Activity的Service。
1.3.3 服务进程:
该进程运行了某个使用startService()启动的Service,此服务进程不直接和用户可以看到的任何部分有关联,服务会运行一些用户关心的事情,比如在后台播放音乐或者通过网络下载文件,因此Android系统会尽量让它们运行直到系统资源低到无法满足前台和可见进程的运行。
1.3.4 后台(背景)进程:
进程运行一些目前用户不可见的Activity,系统资源低时为保证前台、可见或服务进程运行,可随时杀死该进程;通常系统中有很多进程在后台运行,这些进程保存在LRU列表中,LRU列表可以保证用户最后看到的进程最后被杀死。该进程对用户体验无直接的影响,如果一个Activity正确实现了它的生命周期函数,并保存了它的状态,用户回到该Activity时,该Activity就能够正确恢复之前屏幕上的状态。
1.3.5 空进程:
该进程不运行任何活动的应用程序组件,保持这种进程运行的唯一原因是由于缓存以缩短下次运行某个程序组件时的启动时间;系统会为了进程缓存和内核缓存之间的平衡经常会清除空进程。
Android会依据进程中当前活跃组件的重要程度来尽可能高的估量一个进程的级别,比如说,如一个进程中同时有一个服务和一个可视的Activity,则进程会被判定为可视进程,而不是服务进程。此外,一个进程的级别可能会由于其他进程依赖于它而升高。一个为其他进程提供服务的进程级别永远高于使用它服务的进程。
1.4 Android进程间的通信(IPC)
基于Binder的机制:
Android系统并没有采用Linux系统中那么复杂的进程通信机制,可能是考虑到移动终端的硬件设备或者是其设备内存的问题。Android的Binder是基于OpenBinder来实现的。Binder可以参考Service来了解Android进程的通信。
2.1 什么是线程?
线程是进程中的一个实体,基本思想是将程序的执行和资源分开,只拥有一点必不可少的资源。一个进程可拥有多个线程,可以和同属于同一进程的其他线程共享进程所拥有的所有资源,同一进程中的线程之间可以并发执行,并发程度可以获得显著的提高。线程也具有许多进程所具有的特征,因此被称为轻型进程。
结合Android系统来说,当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,比如:用户的按键事件、用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。
2.2 Android的线程模型
2.2.1 什么是单线程模型?
就是在一个进程中只能有一个线程在运行,剩下的线程必须等待当前的线程执行完了才能运行。
2.2.2 什么是线程安全?
1.可以同时被多个线程调用,而调用者不需要任何动作(同步)来确保线程的安全性。
2.当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用方代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。
Android是单线程模型、线程非安全的。
开发中特别注意:
不要阻塞UI线程(单线程模型导致):会导致无法分发组件,绘制等,使得UI不再响应用户操作,如果UI线程阻塞超过五秒钟,系统将显示“应用程序无响应”对话框。
不要再非UI线程中调用和刷新UI相关的组件(线程非安全导致):UI线程本身会对组件进行调用,其他线程调用必须进行协调,可在其他线程中完成特定操作,再反馈给UI线程进行UI组件的操作,这样所有的UI操作均有UI线程实现,避免出现访问冲突。
2.3 进程与线程
一个Android应用只能存在一个进程,但是可以存在多个线程,也就是说,当应用启动后,系统分配了内存,这个进程的内存不被其他进程使用,但被进程中一个或多个线程共享。宏观地讲所有的进程是并发执行的,而进程中的多个线程同时执行但并不是并发的,系统的CPU会根据应用的线程数触发每个线程执行的时刻,当CPU时间轮到分配某个线程执行时刻时该线程开始执行,执行到下一个线程执行的时,依此轮询,直到线程执行结束。
2.4 进程与线程的重要性
在Android应用的开发中,对进程的属性的修改是有限的,仅仅操作一些属性。对于线程来说,开发者就可以自由的进行操作,一个应用最少具有一个线程,可以有多个线程。合理的应用线程可以提高系统资源的利用率,提高应用的质量,给用户更好的体验,所以每个开发者都应该理解并熟练掌握线程知识。
3 实现线程的主要方法
3.1 通过继承Thread类来实现
· 定义一个线程类,继承Thread类;
· 重写该类中的run()方法:将需要通过线程执行的操作,写入该方法中;
· 定义新建的线程类对象以实现线程操作。
start():启动线程
sleep():线程休眠,交出cpu,线程进入阻塞态,不会释放锁
wait():交出cpu,线程进入阻塞态,并释放锁
interrupt():中断线程,停止正在运行的线程,线程必须在阻塞态
3.2 通过实现Runnable接口来实现
· 和使用Thread类似,定义Runnable对象,并重写其中的run()方法。
3.3 通过实现Callable接口来实现
· 定义Callable对象,并重写其call()方法。
3.4 三种方法的区别:
· Callable可以返回值,其他两个方法不能返回值;
· Callable可以抛出异常,其他两个方法不能抛出异常;
· Callable可以获得一个Future对象,以了解任务的执行情况。
☆☆☆Android Studio实现掌握Thread类的使用方法
1.打开Android Studio,新建工程后,在activity_main.xml中界添加一个按钮。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="lession.example.com.androidlession2019522.MainActivity">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:text="使用Thread类子线程"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:id="@+id/button"
android:textColor="@android:color/holo_red_dark"
android:textSize="20sp" />
</LinearLayout>
</RelativeLayout>
2.在MainActivity中,编写代码。
package lession.example.com.androidlession2019522;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
int count;
class mThread extends Thread{
mThread(String name){
super(name);
}
@Override
public void run() {
while (count<10000)
Log.e("MainActivity",
Thread.currentThread().getName()+"--->"+count++);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
count = 0;
mThread mt1 = new mThread("Td1");
mThread mt2 = new mThread("Td2");
mThread mt3 = new mThread("Td3");
mt1.start();
mt2.start();
mt3.start();
}
});
}
}
运行结果:
这就是进程与线程的使用,如果转载以及CV操作,请务必注明出处,谢谢!