读书笔记(11) Android的线程和线程池
来源:互联网 发布:摇号机软件 编辑:程序博客网 时间:2024/06/05 17:31
这些读书笔记是根据《Android开发艺术探索》和《Android群英传》这两本书,然后将书上的一些知识点做一下记录。方便学习和理解,如果有存在侵犯版权的地方,还麻烦告知。个人强烈建议购买这两本书。真心不错。
本节是和《Android开发艺术探索》中的第11章 “Android的线程和线程池” 有关系,建议先买书查看这一章。
[]主线程和子线程
从用途上来说,线程分为主线程和子线程。
主线程是指进程拥有的线程,在java中默认的情况下一个进程只有一个线程,这个线程就是主线程。主线程也叫 UI 线程,主要的作用是运行四大组件以及处理它们和用户的交互。
子线程也叫工作线程,除了主线程以外的线程都是子线程。子线程主要处理执行耗时操作。
在Android中实现线程的方式除了Thread外,还有AsyncTask,IintentService,HandlerThread。
AsyncTask封装了线程池和Handler,主要是用于在子线程中更新UI。
IintentService是一个服务,在内部采用HandlerThread来执行任务。当任务执行完成后IintentService会自动退出。
HandlerThread是具有消息循环的线程,在内部可以使用Handler。
如果一个后台进程,这个进程中没有活动的四大组件。那么这个进程的优先级就会非常低,在内存不足时,很容易被系统杀死。这就是在广播中启动线程来执行耗时操作不安全的原因。
[]Android中的线程形态
{}AsyncTask
AsyncTask在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程并在主线程中更新UI。
AsyncTask经过几次修改,导致对于不同的API版本的AsyncTask具有不同的表现,尤其在多任务的并发执行上。
AsyncTask< Params, Progress, Result >是一个抽象的泛型类,提供了Params, Progress, Result 这三个泛型参数,如果 AsyncTask 不需要传递具体的参数,那么可以用Java.lang.Void代替。
Params:启动任务执行的输入参数的类型,比如请求的url。
Progress:后台任务的执行进度的类型。
Result :后台任务的返回结果的类型。
private class **AsyncTask extends AsyncTask<String, Integer, String>{ /** * * @param params:String 对应AsyncTask中的第一个参数 * @return:String 对应AsyncTask的第三个参数 * 在线程池中执行,用于执行异步任务 * 通过调用 publishProgress()来调用onProgressUpdate() * 返回值传递给onPostExecute()的参数 */ @Override protected String doInBackground(String... params) { return null; } /** * 在主线程中执行,异步任务执行之前开始被调用,一般用于做一些准备工作 * */ @Override protected void onPreExecute() { super.onPreExecute(); } /** * * @param s:String 对应AsyncTask中的第三个参数 * 在主线程中执行,doInBackground()执行结束之后再运行,doInBackground()返回的值作为此方法的参数 * */ @Override protected void onPostExecute(String s) { super.onPostExecute(s); } /** * * @param values:Integer 对应AsyncTask中的第二个参数 * 在主线程中执行,用于显示任务执行的进度 * */ @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); } /** * 在主线程中执行,异步任务取消时被调用 * */ @Override protected void onCancelled() { super.onCancelled(); }}
执行AsyncTask
new **AsyncTask().execute(Params... params);
onPreExecute()先执行,接着doInBackground()执行,在doInBackground()中调用 publishProgress(),publishProgress()触发onProgressUpdate(),doInBackground()执行完后再执行onPostExecute()。
当异步任务取消时,onCancelled()执行,onPostExecute()不会被调用。
AsyncTask的限制:
1,AsyncTask的对象必须在主线程中创建。
2,execute必须在UI线程中调用。
3,不要在程序中直接调用AsyncTask中的方法。
4,不能在doInBackground(Params… params)中更改UI组件的信息
5,一个AsyncTask对象只能执行一次,即只能调用一次execute()方法。否则会报运行时异常。
6,在 Android 1.6 之前,AsynTask是串行执行任务的,Android 1.6时AsynTask开始采用线程池处理并行任务,Android 3.0开始,为了避免AsynTask带来的并发错误,AsynTask 又采用一个线程池来串行执行任务。但是在Android 3.0之后可以通过AsynTask 的executeOnExecutor()方法来执行并发操作。
AsynTask的doInBackground()是一个抽象方法(继承时必须重写),onPreExecute()、onProgressUpdate()、onPostExecute()、onCancelled()的方法体都是空的,需要选择性的重写。publishProgress()是final修饰的,不能重写,只能去调用(在doInBackground()中调用)。
@MainThreadprotected void onPreExecute() {}@WorkerThreadprotected abstract Result doInBackground(Params... params); @WorkerThreadprotected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); }}@MainThreadprotected void onProgressUpdate(Progress... values) {}@MainThreadprotected void onPostExecute(Result result) {}@MainThreadprotected void onCancelled(Result result) { onCancelled();} @MainThreadprotected void onCancelled() {}
AsyncTask的初始状态为Status.PENDING(准备状态)
//初始状态为准备 private volatile Status mStatus = Status.PENDING;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,}public final Status getStatus() { return mStatus;}
以execute()作为入口来分析一下AsyncTask的执行流程
@MainThreadpublic final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params);}@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: //如果该任务正在被执行则抛出异常 throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: //如果该任务已经执行完成则抛出异常 throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } //任务状态修改为RUNNING(正在运行) mStatus = Status.RUNNING; //调用onPreExecute() onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this;}
{}HandlerThread
HandlerThread 继承了 Thread,是一个可以使用 Handler 的 Thread。它的实现就是在 run() 方法中通过 Looper.prepare() 来创建消息队列,并通过Looper.loop() 来开启消息循环。当不需要再使用HandlerThread 时,可以通过 HandlerThread 对象的 quit() 或者 quitSafely() 来终止线程的执行。
HandlerThread 在内部创建了消息队列,外界需要通过 Handler 的消息方式来通知过 HandlerThread 执行一个具体的任务。
HandlerThread 在IntentService中有具体的体现。
//HandlerThread的run()源码@Overridepublic void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1;}
{}IntentService
IntentService 继承 Service 并且是一个抽象类。
IntentService可用于执行后台耗时任务,当任务执行完成后会自动停止。同时也是Service的原因。这导致它的优先级比单纯的线程要高很多,所以IntentService比较适合执行一些高优先级的后台任务,因为它的优先级高不容易被系统杀死。
//IntentService的onCreate()源码 @Overridepublic void onCreate() { startService(Context, Intent) super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper);}
IntentService第一次启动时, onCreate()被调用,在onCreate()会创建HandlerThread,然后利用它的Looper来构造一个Handler对象mServiceHandler,这样通过mServiceHandler发送的消息最终都会在HandlerThread中执行,从这个角度来看,IntentService可以用于执行后台操作。
//IntentService的onStartCommand()源码 @Overridepublic int onStartCommand(Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}//IntentService的onStart()源码 @Overridepublic void onStart(Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg);}
每次启动IntentService,它的onStartCommand()就会被调用一次,IntentService在onStartCommand()中处理每个后台任务的Intent。
onStartCommand()调用onStart(),在onStart()通过mServiceHandler发送一个消息,这个消息会在HandlerThread中处理。
mServiceHandler收到消息后,会将Intent对象传递给onHandleIntent(),注意这个Intent对象和外界startService(intent)中的Intent是一致的。通过这个Intent即可解析出外界startService(intent)传递的参数。通过这些参数可以区分具体的任务,这样onHandleIntent()就可以对不同的后台任务做处理了。
//IntentService的ServiceHandler类源码 private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { onHandleIntent((Intent)msg.obj); stopSelf(msg.arg1); }}
当onHandleIntent()执行结束后,IntentService会通过stopSelf(msg.arg1)来尝试停止服务。
采用stopSelf(msg.arg1)而不是stopSelf()来停止服务,是因为stopSelf()会立刻停止服务,而这时可能还有其他的消息未处理,stopSelf(msg.arg1)则会等待所有的消息都处理完毕才停止服务。
stopSelf(msg.arg1)在尝试停止服务之前会判断最近启动服务的次数是否和startId相等,如果相等就立刻停止,不相等则不停止。
IntentService的onHandleIntent()需要我们在子类中实现,它的作用是从intent参数中区分具体的任务并执行这些任务。
如果目前只有一个后台任务,那么onHandleIntent()方法执行完这个任务,stopSelf(msg.arg1)就直接停止服务,
如果目前有多个后台任务,那么当onHandleIntent()方法执行完最后一个任务,stopSelf(msg.arg1)才会停止服务,
由于每执行一次后台任务就必须启动一次IntentService,而IntentService内部是通过消息的方式向HandlerThread请求执行任务,Handler中的Looper是顺序处理消息的,所以IntentService也是顺序执行后台任务的。当有多个后台任务同时存在时,这些后台任务会按照外界发起的顺序排队执行。
[]线程池
线程池的优点:
1,重用线程池中的线程,避免因为线程的创建和销毁带来的性能开销。
2,能有效控制线程池的最大并发数,避免大量的线程之间互相抢占系统资源而导致的阻塞现象。
3,能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能。
线程池来源于Executor接口,真正的线程实现为ThreadPoolExecutor,根据线程池的功能特征上来说,线程池主要可以分为4类 FixedThreadPool,CachedThreadPool,ScheduledThreadPool,SingleThreadExecutor,这4类可以通过Executors的工厂方法来得到。
{}ThreadPoolExecutor对象的创建
ThreadPoolExecutor mThreadPoolExecutor= new ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
corePoolSize参数:线程池的核心线程数,默认情况下,核心线程会在线程池中一直存活,即使他们处于闲置状态,如果将ThreadPoolExecutor的allowCoreThreadTimeOut()设置为true,那么闲置的核心线程在等待新任务到来时会有超时策略,这个时间间隔由keepAliveTime指定,当等待时间超过keepAliveTime指定的时长,核心线程就会停止。
maximumPoolSize参数:线程池所能容纳的最大线程数,当活动线程数达到这个数值后,后续的新任务会被阻塞。
keepAliveTime参数:非核心线程闲置时的超时时长,超过这个时长,非核心线程就会被回收,当ThreadPoolExecutor的allowCoreThreadTimeOut()设置为true,keepAliveTime同样会作用于核心线程,
unit参数:用于指定keepAliveTime参数的时间单位,这是一个枚举,常见的有TimeUnit.MILLISECONDS(毫秒),TimeUnit.SECONDS(秒), TimeUnit.MINUTES(分钟),
workQueue参数:线程池中的任务队列,通过线程池的execute()提交的Runnable对象会存储在这个参数中。
threadFactory参数:线程工厂,为线程池提供创建新线程的功能,ThreadFactory 是一个接口,它只有一个方法 newThread()。
handler参数:这个参数不常使用,当线程池无法执行新任务时,可能是由于任务队列已满或者是无法成功执行任务,这个时候ThreadPoolExecutor就会调用handler的rejectedExecution()来通知调用者。默认情况下rejectedExecution()会直接抛出一个RejectedExecutionException。ThreadPoolExecutor为RejectedExecutionHandler提供了几个可选值:CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy。其中AbortPolicy是默认值,它会直接抛出RejectedExecutionException。
{}ThreadPoolExecutor的执行任务规则
1,如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
2,如果线程池中的线程数量已经达到或者超过核心线程的数量,那么任务会插入到任务队列中排队等待执行。
3,如果无法将任务插入到任务队列中,这可能是由于任务队列已满,这时如果线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程数来执行任务。
4,如果线程数量已经达到线程池规定的最大值,那么就拒绝执行任务。ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution()来通知调用者。
{}FixedThreadPool
FixedThreadPool是通过Executors的newFixedThreadPool()方法来创建的,它是线程数量固定的线程池,当线程处于空闲状态时,它们不会被回收,除非线程池被关闭了,当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来,
FixedThreadPool只有核心线程(核心线程数和容纳的最大线程数相等)并且这些核心线程不会被回收,这意味着它能够快速的响应外界请求。
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(int nThreads)public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor( nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue< Runnable>());}
{}CachedThreadPool
CachedThreadPool是通过Executors的newCachedThreadPool()方法来创建的,它是一个线程数量不定的线程池。它只有非核心线程,并且最大线程数是一个很大的数(Integer.MAX_VALUE),实际上就相当于最大线程数可以任意大。
当线程池中的线程都处于活动状态时,线程池会创建新的线程来处理新任务,否则就会利用空闲的线程来处理新任务。线程池中的空闲线程都有超时机制,这个超时时长为60秒,超过60秒闲置线程就会被回收
CachedThreadPool主要用于执行大量的耗时较少的任务,当整个线程池都处于闲置状态时,线程池中的线程都会超时而被停止,这时CachedThreadPool中实际上是没有任何线程的。
ExecutorService cachedThreadPool= Executors.newCachedThreadPool()public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor( 0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());}
{}ScheduledThreadPool
ScheduledThreadPool是通过Executors的newScheduledThreadPool()方法来创建的,它的核心线程数量是固定的,而非核心线程数量是没有限制的,并且当非核心线程闲置时会被立即回收,
ScheduledThreadPool主要用于执行定时任务和具有固定周期的重复任务。
ExecutorService scheduledThreadPool =Executors.newScheduledThreadPool(int corePoolSize)public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize);}public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue());}
{}SingleThreadExecutor
SingleThreadExecutor是通过Executors的newSingleThreadExecutor()方法来创建的,它只有一个核心线程,它确保所有的任务都在同一个线程中按顺序执行。
SingleThreadExecutor主要用于统一所有的外界任务到一个线程中,这使得在这些任务之间不需要处理线程同步的问题。
ExecutorService singleThreadExecutor= Executors.newSingleThreadExecutor()public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor( 1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));}
{}线程池的使用
Runnable command = new Runnable() { @Override public void run() { }};ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);fixedThreadPool.execute(command);ExecutorService cachedThreadPool = Executors.newCachedThreadPool();cachedThreadPool.execute(command);ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(4);//2000ms后执行commandscheduledExecutor.schedule(command, 2000, TimeUnit.MILLISECONDS);//延时10ms后,每隔1000ms执行一次commandscheduledExecutor.scheduleAtFixedRate(command, 10, 1000, TimeUnit.MILLISECONDS);ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();singleThreadExecutor.execute(command);
- 读书笔记(11) Android的线程和线程池
- 读书笔记-Android开发艺术探索-第11章-Android的线程和线程池
- 【读书笔记】【Android 开发艺术探索】第11章Android 的线程和线程池
- Android开发艺术探索读书笔记(第11章 Android的线程和线程池)
- Android的线程和线程池————读书笔记
- Android的线程和线程池
- Android的线程和线程池
- Android的线程和线程池
- Android的线程和线程池
- 十一、Android的线程和线程池
- Android的线程和线程池
- Android的线程和线程池(一)
- Android的线程和线程池
- Android的线程和线程池
- Android的线程和线程池
- Android的线程和线程池
- Android的线程和线程池
- Android 的线程和线程池
- ViewPager广告中的图片请求自网络,监听跳转至点击图片对应Url的webView
- 一个高性能RPC框架原理剖析
- 跨终端Web之Hybrid App开发对比
- 进击的RecyclerView入门三(要是能拖动就好了)
- Android横竖屏切换时不销毁Activity
- 读书笔记(11) Android的线程和线程池
- 点击页面其他地方,隐藏DIV(常用)
- 安卓调试adb server didn't ack问题
- CentOS 6.4下Squid代理服务器的安装与配置
- CentOS 安装 Tomcat
- 传递参数到highchart
- log4cpp测试
- Jquery table
- android ndk调用Log.getStackTraceString(new Throwable())输出堆栈信息