目前正在阅读《Android开发进阶-从小工到专家》,书很赞,对于我这种初级人员来说挺有帮助,我希望能坚持把这个读书笔记写完,有所收获,内化成自己的知识储备。
本读书笔记只是针对个人作为学习记录而言。对应的java练习源码可以在这里下载之前写过Android的消息机制 http://blog.csdn.net/mr_immortalz/article/details/51066869,感觉之前写的就挺好的,就不再记录了。
1.Thread也是一个Runnable,它实现了Runnable接口;在Thread类中有一个Runnable类型的target字段,代表要被执行在这个子线程的任务。
2.实际上最终被线程执行的任务是Runnable,而非Thead。Thread只是对Runnable的包装。
3.当启动一个线程时,如果Thread的target(即Runnable)不为空,则会在子线程中执行这个target(即Runnable)的run,否则执行该线程自身的run函数。
new Thread(){
@Override
public void run() {
//耗时操作,此时target为空
}
}.start();
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
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数名 | 作用 |
---|---|
corePoolSize | 线程池中所保存的核心线程数,线程池启动后默认为空 |
maximumPoolSize | 线程池允许创建的最大线程数 |
keepAliveTime | 当前线程池线程总数大于核心线程数时,终止多余的空闲线程的时间 |
unit | keepAliveTime参数的时间单位,可选值有毫秒、秒、分等。 |
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类,并非某个具体对象。
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.公平性
常用形式
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
这个是AsyncTask的几个状态
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开发进阶-从小工到专家》