线程:是系统进行运算调度的最小单位
进程:是线程的容器,是系统进行资源分配和调度的基本单位,一个进程可以并发多个线程
在Android中,系统启动时默认创建主线程,但是主线程(UI线程)不能进行耗时操作,否则android程序会无响应,所以当有耗时等操作的时候就可以创建一个子线程。
使用线程的优点:
1.资源利用率更高
例如从磁盘读取文件的时候,读取一个文件5s,处理一个文件2s,当需要读取2个文件,但只有一个单线程的时候,他就会顺序去执行,先读取A并处理完A文件的时候,才回去读取B,这样花费的时间需要14s,但是CPU时间还有很多空闲。当使用两个线程时,就能读取完A后,同时开始处理A和读取B文件的操作,这时候CPU时间使用更多,最终花费时间只需要12s
2.程序响应更快
例如一个人服务器程序是单线程的,此时如果一个请求需要占用大量的时间在这段时间内新的客户端就无法发送请求给服务器端,如果引入多线程则会大大提高效率。
从一个单线程的应用到多线程的应用并不仅仅带来好处,其也会带来一些代价,不要仅仅为了使用多线程而使用多线程,应该明确在使用多线程的时候能带来的好处比付出的代价大的时候,才使用多线程。
但是有优点,当然也有缺点,现在介绍一下缺点。
使用线程的缺点:
1.等候共享资源会变慢:
当两个线程同时需要使用一个资源的时候,就会出现占用,降低运行时间
2.对线程管理产生额外的开销:
程的使用会给系统带来上下文切换的额外负担。当这种负担超过一定程度时,多线程的特点主要表现在其缺点上,比如用独立的线程来更新数组内每个元素。
3.线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状。
4.对公有变量的同时读或写。当多个线程需要对公有变量进行写操作时,后一个线程往往会修改掉前一个线程存放的数据,从而使前一个线程的参数被修改;另外 ,当公用变量的读写操作是非原子性时,在不同的机器上,中断时间的不确定性,会导致数据在一个线程内的操作产生错误,从而产生莫名其妙的错误,而这种错误是程序员无法预知的。
当然以上的缺点只要涉及合理都是可以避免的
但是设计开销会增加就无法避免。
android四种常用的操作多线程的方式
1、Handle机制(最常用)
Handle 的一些常用参数解释:
Message:消息,就是一个载体,包含消息ID,消息处理对象和处理的数据等(msg.what ,msg.arg ,msg.obj等).
Handler:用于同一个进程的线程间通信,消息处理者,专门负责Message的发送和处理。我们使用Handler时,一般通过handleMessage(Message msg)来处理Message,也就是统一处理消息的回调,确保自己发出的消息也是自己来处理。
MessageQueue:队列,就是存放Handler发送过来的消息,按照先进先出的顺序规则来执行。将链表的数据结构以Message来串联起来,等待Looper的抽取MessageQueue,其他非主线程需要looper的时候就会通过调用prepare函数来实现。
Looper:首先要理解一个线程是一段可执行的代码,作为App的主线程,不能让代码执行完,因为代码执行完的话app就会自动退出,因此不能让主线程不能让代码段执行,只能在代码中插入一个死循环,这时候Looper的作用就体现出来了,将主线程变成Looper线程。并且这时主线程就会在等其他线程发消息(更新UI和Activity状态等等)那,另外,Looper不断从消息队列拿出消息给主线程,也就是无限循环去查找是否有消息,有就去处理,没有的话就一直等待,一个MessageQueue需要一个Looper。
Thread:负责调度整个消息的循环
怎么利用Handle,让主线程与子线程通信?
答:可以利用HandlerThread进行生成一个子线程的Handler,并且实现handlerMessage方法,然后在主线程里面也生成一个Handler,然后通过调用sendMessage方法进行通知子线程。同样,子线程里面也可以调用sendMessage方法进行通知主线程。这样做的好处比如有些图片的加载啊,网络的访问啊可能会比较耗时,所以放到子线程里面做是比较合适的
Handle 实例
1.创建一个线程
创建一个子进程,并让其休眠,模拟执行一个耗时操作
public class HandleTest extends Thread{
//Thread build
private String name; //Thread name
public HandleTest(String name){
this.name=name;
}
static int i = 5;
public void run(){
Message msg = new Message();
try {
//sleep set 8000
i = 3;
sleep(8000);
msg.what = 1;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在里面创建一个整型常量3,当结束的时候传出参数,并输出1333,但是在子线程没办法传回参数3,因为run是一个void返回值,这时候怎么办?
public class HandleTest extends Thread{
//Thread build
private String name; //Thread name
public HandleTest(String name){
this.name=name;
}
static int i = 5;
public void run(){
//instantiation message
Message msg = new Message();
try {
//sleep set 8000
i = 3;
sleep(8000);
// send messge.what = 1 to handle.message
msg.what = 1;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
有两种解决办法,判断msg.what或回调msg数据
2.实例化handle类,并建立message,传递参数
在主线程创建一个handle
static int i = 1;
public void handleMessage(){
//When receiving the msg.what == 1,i = 3;
switch (msg.what) {
case 0:
i = 3;
break;
}
}
通过判断回调msg.what修改参数,同时也可以用msg.args回调整型参数