《Android开发进阶-从小工到专家》-Android中的多线程读书笔记

目前正在阅读《Android开发进阶-从小工到专家》,书很赞,对于我这种初级人员来说挺有帮助,我希望能坚持把这个读书笔记写完,有所收获,内化成自己的知识储备。
本读书笔记只是针对个人作为学习记录而言。对应的java练习源码可以在这里下载

之前写过Android的消息机制 http://blog.csdn.net/mr_immortalz/article/details/51319354,感觉之前写的就挺好的,就不再记录了。

一.多线程的实现 - Thread和Runnable

1.Thread也是一个Runnable,它实现了Runnable接口;在Thread类中有一个Runnable类型的target字段,代表要被执行在这个子线程的任务。

2.实际上最终被线程执行的任务是Runnable,而非Thead。Thread只是对Runnable的包装。

3.当启动一个线程时,如果Thread的target(即Runnable)不为空,则会在子线程中执行这个target(即Runnable)的run,否则执行该线程自身的run函数。

1
2
3
4
5
6
new Thread(){
@Override
public void run() {
//耗时操作,此时target为空
}
}.start();
1
2
3
4
5
6
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作,此时target不为空
}
}).start();

常用函数

函数名作用
wait当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去了对象的机锁,使得其他线程可以访问。用户可以用notify、notifyAll或者指定睡眠时间来唤醒当前等待池中的线程。注意:wait、notify、notifyAll必须放在synchronized block中,否则会抛出异常。
sleep该函数是Thread的静态函数,作用是使当前线程进入睡眠状态,因为其是静态方法,所以不会改变对象机锁。即使睡着也持有对象锁
join等待目标线程完成后再执行
yield让出执行权限,让其他线程得以优先执行,但其他线程能否优先执行是未知的。

见demo源码

与多线程相关的方法 - Callable、Future、FutureTask

这里写图片描述

二.线程池分类

类型作用
FixedThreadPool
CachedThreadPool
ScheduledThreadPool
SingleThreadExecutor

1.启动指定数量的线程——ThreadPoolExecutor

1
2
3
4
5
6
7
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数名作用
corePoolSize线程池中所保存的核心线程数,线程池启动后默认为空
maximumPoolSize线程池允许创建的最大线程数
keepAliveTime当前线程池线程总数大于核心线程数时,终止多余的空闲线程的时间
unitkeepAliveTime参数的时间单位,可选值有毫秒、秒、分等。
workQueue任务队列
threadFactory线程工厂,通常不需要设置
handler拒绝策略,当线程池和workQueue都满了情况下,对新任务采取的处理策略

这里写图片描述

这里写图片描述

2.定时执行一些任务——ScheduledThreadPoolExecutor


见demo源码

三.同步集合

程序中的优化策略——CopyOnWriteArrayList

见demo源码


其基本思路是:从多个线程共享同一个列表,当某个线程想要修改这个列表的元素时,会把列表中的元素Copy一份,然后进行修改,修改完成之后再将新的元素设置给这个列表,这是一种延时懒惰策略。

这里有博文介绍
http://ifeve.com/java-copy-on-write/

提高并发效率——ConcurrentHashMap

HashTable是HashMap的线程安全实现,但HashTable使用synchronized来保证线程安全,所以在竞争激烈的并发环境下表现出效率低下(所有访问HashTable的线程都必须竞争同一把锁)。
而ConcurrentHashMap使用锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据分配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。有些方法需要跨段,如size、containsValue,他们可能需要锁定整个表而不仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。

这一篇博文有介绍例子:
http://blog.csdn.net/xuefeng0707/article/details/40834595
http://ifeve.com/concurrenthashmap/

有效的方法——BlockingQueue


参考这篇博文
http://ifeve.com/java-blocking-queue/

四.同步锁

同步机制关键字——synchronized


每个对象都只有一个锁。
synchronized作用于函数时,实际上锁定的就是该函数所在类的 对象。
synchronized作用于class时则是锁的这个Class类,并非某个具体对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class SynchronizedDemo {
public synchronized void synchMethod() {
//同步方法,锁对象
}
public void syncThis() {
synchronized (this) {
//同步块,锁对象
}
}
public void syncClassMethod() {
synchronized (SynchronizedDemo.class) {
//同步class对象,锁Class对象
}
}
public synchronized static void syncStaticMethod() {
//同步静态方法,锁Class对象
}
}

显示锁——ReentratLock与Condition

显示锁ReentratLock和内置所synchronized相比,具有更高灵活性
1.获取和释放的灵活性
2.轮询锁和定时锁
3.公平性

常用形式

1
2
3
4
5
6
7
8
9
10
11
12
Lock lock = new ReentrantLock();
public void doSomething(){
lock.lock();
try {
//执行某些操作
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}

注意:当JVM用synchronized管理锁定请求和释放时,JVM在生成线程转储时能够包括锁定信息(能标示死锁或者其他异常行为的来源0)。Lock类只是普通类,JVM不知道具体哪个线程拥有Lock对象。

见demo源码

http://blog.csdn.net/u013256816/article/details/50445241 JAVA线程间协作:Condition

信号量Semaphore
Semaphore是一个计数信号量,它的本质是一个“共享锁”。信号量维护了一个信号量许可集,线程可以通过调用acquire()来获取信号量的许可。当信号量中有可用的许可时,线程能获取该许可,否则线程必须等待,直到有可用的为止

见demo源码

hongyang大神的这篇文章用到了信号量
Android Handler 异步消息处理机制的妙用 创建强大的图片加载类
(之前看过有点傻傻分不清,现在算是有点小理解了)
http://blog.csdn.net/lmj623565791/article/details/38476887

五.创建异步任务更简单——AysncTask的原理

这个是AsyncTask的几个状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,//待定
/**
* Indicates that the task is running.
*/
RUNNING,//执行
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,//结束
}

注意:一个任务实例只能执行一次,如果执行第二次将会抛出异常

因为每次在执行execute的时候会去判断当前mState状态,如果不是PENDING,则抛出异常,而每次执行完毕后mState=FINISHED,所以一个任务实例只能执行一次,如果执行第二次将会抛出异常

实现一个简单的AsyncTask

见demo源码

对应的java源码下载地址(仅java源码,不是一个工程)
http://download.csdn.net/detail/mr_immortalz/9516511

推荐网址 http://ifeve.com/java-copy-on-write/
阅读书籍《Android开发进阶-从小工到专家》