线程池:
1.共有四种:Executors
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
可以使用自己提供的 ThreadFactory 创建新线程。
上面几个方法返回ExecutorService对象。调用execute方法执行任务。
2.改线程设置优先级:
a.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);在线程里的run方法中调用就行
b.调用线程的.setPriority();方法
把工作线程设置为后台类型,防止抢占UI资源。默认的为Default,归于default cgroup,会平等的和UI线程争夺CPU资源。
3.AsyncTask的使用:线程优先级为background,对UI线程的执行影响极小。串行和并行和版本有关。
a.取消任务:
我们可以随时调用 cancel(boolean)去取消这个加载任务,调用这个方法会间接调用 iscancelled 并且返回true 。
当调用cancel()后,在doInBackground()return后 我们将会调用onCancelled(Object) 不在调用onPostExecute(Object)
//注:但是doInBackground()方法会继续执行,只是不在调用onPostExecute
为了保证任务更快取消掉,你应该在doInBackground()周期性的检查iscancelled 去进行判断。
**注意,我们的oncancel和onPostExecute一样,都是在UI线程中执行。。。所以当我们想要取消之后,有些界面变化 我们可以在oncancel里面改变UI.
某些情况下,我们调用cancel(true)可能就会失效
比如 :task已经加载完成,或者 已经取消过一次,或者是其他情况
4.线程池特点:
Thread(),AsyncTask适合处理单个任务的场景,HandlerThread适合串行处理多任务的场景。当需要并行的处理多任务之时,ThreadPoolExecutor是更好的选择。
线程池可以避免线程的频繁创建和销毁,显然性能更好,
但线程池并发的特性往往也是疑难杂症的源头,是代码降级和失控的开始。多线程并行导致的bug往往是偶现的,不方便调试,一旦出现就会耗掉大量的开发精力。
5.IntentService
IntentService又是另一种开工作线程的方式,从名字就可以看出这个工作线程会带有service的属性。和AsyncTask不同,没有和UI线程的交互,也不像HandlerThread的工作线程会一直存活。
IntentService背后其实也有一个HandlerThread来串行的处理Message Queue,从IntentService的onCreate方法可以看出。
只不过在所有的Message处理完毕之后,工作线程会自动结束。所以可以把IntentService看做是Service和HandlerThread的结合体,适合需要在工作线程处理UI无关任务的场景。
Android开线程的方式虽然五花八门,但归根到底最后还是映射到linux下的pthread,业务的设计还是脱不了和线程相关的基础概念范畴:
线程的执行顺序,调度策略,生命周期,串行还是并行,同步还是异步等等。摸清楚各类API下线程的行为特点,在设计具体业务的线程模型的时候自然轻车熟路了,
线程模型的设计要有整个app视角的广度,切忌各业务模块各玩各的。
6.HandlerThread
HandlerThread背后只有一个线程,所以任务是串行执行的。串行相对于并行来说更安全,各任务之间不会存在多线程安全问题。
HandlerThread所产生的线程会一直存活,Looper会在该线程中持续的检查MessageQueue。这一点和Thread(),AsyncTask都不同,thread实例的重用可以避免线程相关的对象的频繁重建和销毁。
HandlerThread较之Thread(),AsyncTask需要写更多的代码,但在实用性,灵活度,安全性上都有更好的表现。
使用步骤
尽管HandlerThread的文档比较简单,但是它的使用并没有想象的那么easy。
创建一个HandlerThread,即创建了一个包含Looper的线程。
HandlerThread handlerThread = new HandlerThread("123");
handlerThread.start(); //创建HandlerThread后一定要记得start()
获取HandlerThread的Looper
Looper looper = handlerThread.getLooper();
创建Handler,通过Looper初始化
Handler handler = new Handler(looper);
通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit();。
7.Timer和ScheduledExecutorService
优先使用ScheduledExecutorService来做周期性定时任务。ScheduledExecutorService需要在生命周期方法中去处理,在页面不可见时调用shutdownNow();shutdown;方法。