线程安全:
在多线程的情况下,不会因为线程之间的操作而导致数据错误。
线程同步:
同一个资源,可能在同一时间被多个线程操作,这样会导致数据错误。这是一个现象,也是一个问题,而研究如何解决
此类问题的相关工作就叫做线程同步。
android中,处理线程同步的手段就是:锁
一般分为公平锁和非公平锁:
synchronized(内部锁,互斥锁):
synchronized是JVM提供的线程同步机制,如果出现问题,JVM能捕获异常,并释放资源,具体实现机制需要查看JVM源码
synchronized的使用特点:
lock接口:
这些实现了lock接口的锁定义是通过java语言进行实现与封装的,具体的实现机制可以通过查看其源代码得知
lock实例加锁和解锁的大概过程:
当一个资源被锁定之后,访问它的线程会被加入等待队列,当
内部锁(互斥锁)ReentrantLock
读写锁
synchronized
1.synchronized作用在方法上:锁对象
2.synchronized作用在代码块:只锁代码块
3.synchronized(this):对象锁
4.synchronized(object):成员锁
总结synchronized:
可以锁对象:synchronized(this) , synchronized(class) , synchronized methods , 此时对象的所有
资源不能被其他线程访问
成员锁:
synchronized(obj){ } , 代码段内的代码不能被同时访问。
对象锁太粗糙
通常情况使用synchronized就够了,资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,才会使用
ReetrantLock来完成复杂的业务需求。(不公平锁)
使用java封装的锁对象可以更灵活的满足业务需求,比如可以设定锁的等待时间,公平性等等,而使用Synchronized
则只能使用同步监视器的三个方法来操作线程
线程通讯:
synchronized作为对象锁时候,通过this,可以调用三个方法在线程之间通讯
synchronized作为成员所时候,通过(obj),调用三个方法,其中被锁的东西就叫做同步监视器。(this,obj)
wait:当前线程进入等待状态,直到其他线程调用该同步监视器的notity方法或者notityall方法来唤醒.
调用wait就以为着释放同步监视器
notify:唤醒在此同步监视器上等待的单个线程。如果所有线程都在此同步监视器上等待,则会随机选择唤醒其中一个线程。
只有当前线程放弃对该同步监视器的锁定后(用wait方法),才可以执行被唤醒的线程
notityAll: 唤醒在此同步监视器上等待的所有线程。只有当前线程放弃对该同步监视器的锁定后,才能执行唤醒的线程。
线程模型:
消息循环
消息队列
handler
Thread
UI Thread
android的线程模型:
UI线程有一个消息队列,一个消息循环,一个Handler.
一般建立的后台线程对象就是一个一次性完成工作的任务.
如何建立他们之间的联系?
一般情况下,启动一个非UI线程用于处理耗时工作之后,需要一个机制用于通知UI线程,工作做好了,
这个机制就是一个Message。
当后台线程工作结束之后,向欲通知的线程发送一个Message,用来通知这个目标线程说:“我已经工作完了”,而这个
Message怎么发过去呢?通过Handler对象。 想给哪个线程发送Message就给该线程的Handler发送Message.
(前提是目标线程有处理消息的能力)
综上:
当后台线程完成工作之后,会通过UI线程的Handler对象发送一个Message到UI线程的消息队列中,UI线程的消息循环
就会从消息队列中取出此Message,并且处理此Message,做爱做的事。
对于一个后台线程:
如果想让该 线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。 如下例所示:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
这样你的线程就具有了消息处理机制了,在Handler中进行消息处理。