Android中的线程和线程池

来源:互联网 发布:xp打开关闭windows功能 编辑:程序博客网 时间:2024/05/29 02:39

主线程的作用是运行四大组件:活动、服务、广播、内容提供器,以及它们和用户的交互,子线程主要是执行耗时操作,子线程也叫做工作线程

1.AsyncTask:

AsyncTask是方便开发者在子线程中更新UI,内部是封装了线程池和Handler

AsyncTask是一个抽象的泛型类,它的三个参数,第一个是传递参数,第二个是进度的显示数据类型,第三个是后台任务执行完后传递给结果处理方法的;在不需要某个参数时使用Void类来代替。

五个方法:

onPreExecute,在异步任务执行前执行,一般用于做一些准备工作

doInBackground方法是在线程池里执行的,通过publishProgress方法来发布进度消息给监听进度的方法

onProgressUpdate接受到publishProgress传递过来的进度后,在主线程里执行UI的更新

onPostExecute监听doInBackground方法执行完结束,并接受结果,然后在主线程对结果进行处理

onCancelled取消异步任务

用AsyncTask子类的实例的execute来执行异步,在执行完任务后就会关闭AsyncTask


注意事项:

AsyncTask的对象必须要在主线程中创建,这点很重要

Execute方法必须在UI线程调用

除了onCancelled方法,其他方法不要主动调用

一个AsyncTask对象只能执行一次,execute只能调用一次

AsyncTask是主要异步操作是执行在线程池里,一个AsyncTask执行线程池里的一个线程,这个线程池默认是串型的,也就是说,当有多个AsyncTask时,它们会一个个执行,不会并发执行;可以使用executeOnExecuter来代替execute方法,然后传递多一个指定的参数进去来让其进行并发操作


2.IntentService:

IntentService是可以更方便地执行后台任务,内部是采用HandlerThread来执行任务,单独地开启线程来执行后台任务容易被系统杀死,而放在服务里就不容易,这是IntentService的优点

HandlerThread是一个内部创建了消息循环的线程;在不需要时要quit结束它,因为它内部是一个无限循环

IntentService在执行完任务后会自动的停止,比较适合执行一些高优先级的后台任务;在实现上,IntentService封装了HandlerThread和Handler

IntentService也是顺序地执行后台任务的,当有多个IntentService时,会按照外界发起的顺序排队执行任务

继承自IntentService后要重写onHandleIntent方法


3.线程池:

线程池地3大优点:

重用线程池中的线程,避免创建销毁带来的开销,即节约开销

有效控制线程的最大并发数,避免量线程之间互抢资源导致阻塞,即控制并发访问资源

管理,并提供定时执行以及执行间隔循环执行,即执行管理


ThreadPoolExecutor(实现了ExecutorService接口)用来创建、初始化线程,需要指定几个参数来指定要创建的线程池的属性:

corePoolSize,核心线程的数量,核心线程池默认是一直存活的,可以通过设置allowCoreThreadTimeOut为true来根据keepAliveTime所设置的时间来回收核心线程

maximumPoolSize,最大线程池,达到这个值以后,后续的新线程会被阻塞

keepAliveTime,一般情况下只用来指定非核心线程的闲置时间

unit,用于指定keepAliveTime的时间单位

workQueue,任务队列

threadFactory,线程工厂,为线程池提供创建新线程的功能


ThreadPoolExecutor的执行过程如下:

如果线程的数量没有达到核心线程的数量,就创建核心线程

如果线程的数量达到了核心线程的数量,就会将任务放进任务队列中等待执行

如果线程的数量达到了核心线程的数量,并且任务队列也满了,就会创建一个非核心线程来执行任务

如果线程的数量达到了核心线程的数量,并且任务队列满了,并且非核心数量加上核心数量已经超过指定的最大线程数,就会拒绝任务

*需要注意的是,线程放进队列是当核心线程的数量够了时,而不是指定的最大线程数够了时,这里的线程是指核心线程;开启非核心线程是当队列满了时,而不是指定的核心线程数达到时。也就是说,队列是用来存放核心线程的,非核心线程没有队列,它是在核心线程不能够再多的时候才创建的


通过配置ThreadPoolExecutor可以实现很多特定的线程池,而Android中有4类常用的线程池,它们也是通过配置TPE来实现的:

FixedThreadPool,fixed的意思是固定的,也就是说是一个线程数量固定的线程池,而固定也就意味着它的线程都是核心线程,它们都不会被回收,没有超时机制

CachedThreadPool,缓存线程池,它和上一个完全相反,它只有非核心线程,它的数量可以任意大,有超时机制,这类线程池适合执行大量的耗时比较少的任务,当所有线程的任务执行完后,它几乎是不占用任何系统资源的,因为超时之后没有线程了

ScheduledThreadPool,规划线程池,它是有固定的核心线程,数量不限的非核心线程,适合执行定时任务和具有固定周期的重复任务

SingleThreadExecutor,单核线程池,它只有一个核心线程,也就是说,所有的任务都要这个线程来处理,这样可以保证任务的按顺序执行,适合必须要顺序执行的任务

上面4种方法使用多态的创建:ExecutorService xxx = Executors.new+上述线程池名称(需要的数量参数); 然后xxx.execute(没有调用开始方法的任务Runnable/Callable/Thread实例和必要的配置参数)来使用


另外一种方式是调用submit方法:

Future<?> submit(Runnable task) (Future为null,这个方法其实没有返回值)

Future<T> submit(Runnable task, T result)

Future<T> submit(Callable<T> task)

方法返回一个Future对象,可以使用该Future对象进行线程池控制,比如调用Future对象的isDone判断是否执行完,用cancel取消任务,用isCancel判断是否被取消等

当某个线程池执行已经不需要再使用时,使用该线程池对象的shutdown关闭


原创粉丝点击