Android多线程Thread Runnable Handler AsyncTask等之间的关系

  • 转自:点击打开链接

  • android 的多线程实际上就是java的多线程。android的UI线程又称为主线程。

  • 首先是Thread 和 Runnable:

    Thread才是一个线程,而Runnable可以理解为一个任务。这个任务只是一个接口。具体的任务执行是在 run()方法执行。

    Thread thread = new Thread(Runnable);

    那么就是把一个Runnable任务放到线程里面。当调用thread.start() 的时候,系统新开一个线程去执行,这个runnable任务是在多线程执行的。是在新开的线程执行的。

    但是thread.run() ,这样子实际上只是在UI线程执行了Runnable 并没有实现多线程。系统也没有新开一个线程。

    如果直接 new Runnable().run();那么实际上是直接在UI线程执行了这个任务没有进行一个多线程的操作。

    总结:runnable()只是一个任务的抽象,并不是多线程。Thread.start()。才是新开一个多线程。并且在新开的线程执行Thread你们的run()方法。

    来看看android 的多线程通信机制的产物 Handler。

    下面这3个方法的hanlder实际上是不涉及多线程的。

    post(Runnable) 让当前线程执行Runnable任务。如果是在主线程调用,那么就是在UI线程执行Runnable。实际上没有多线程执行runnable。
    postAtTime(Runnable,long) 也是让当前线程在 时间点long 执行Runnble
    postDelayed(Runnable long) 让当前线程延时 long 后执行Runnable。

    这3个方法实际上可以把handler看着是一个任务调度器,而不是一个多线程相关的。

    sendEmptyMessage(int)
    sendMessage(Message)
    sendMessageAtTime(Message,long)
    sendMessageDelayed(Message,long) 发出消息的方法

    handleMessage(Message msg)处理消息 这才是android 的hanlder的多线程通信用到的,看下图

    \

    可以看到3个线程共用一个消息队列Message Queue,一个消息循环器Looper(作用不断循环读取消息队列的消息)。

    另外2个线程通过hanlder的sendMessage等方法发送Message,message中可以包含数据。或者是一些action的标记值。

    主线程的hanlder通过handleMessage把包含数据等信息的消息取出来。这个过程中其他线程的数据通过message+hanlder传递到主线程实现的多线程通信。

    好的最后再说AsyncTask,可以开启一个多线程执行任务,并且多线程的数据传递也是有这个类自己完成。

    实际上AsyncTask 是由 thread + handler的封装实现。所以AsyncTask 跟Thread+handler实现没有本质的差别。

    AsyncTask的代码更少,使用比Thread+handler简单。

    主要有 onPreExecute() ; 是指在执行多线程任务之前的一个初始化执行。在UI线程调用

    doInBackground(Params... params);这个方法是AsyncTask新启动的线程实现的。在新线程调用
    onPostExecute(Result result) ; 这个是doInBackground()方法执行完成后,才调用的方法。

    result 就是doInBackground()的结果,就是用Hanlder的方式传递的数据。这个方法在UI线程调用

    protected void onProgressUpdate(Progress... values);处理中间数据。doInBackGround()方法中,即在新开的线程中调用publishProgress方法,那么hanlder就把publishProgress的值传递到UI线程中。

    并且把值交给onProgressUpdate方法处理。所以onProgressUpdate是在UI线程调用的。

    看看AsyncTask 的源码。

    AsyncTask是基于线程池的实现。所以先学习一下线程池。

    线程池可以这样理解:一些线程的集合。假设我们这个线程池容量是20.

    那么一个新的任务来了,我们想去看看我们线程池的有没有线程处于休眠状态,有就唤醒然后让他去处理任务。处理完成后线程休眠而不是直接结束线程。

    没有处于休眠状态的线程,那么就意味着20个线程都在工作。系统比较忙,那么就让这个任务排队。

    如果忽然来了1000个任务--那么有20个进入线程中处理。另外的980个任务排队。这样子保证系统高效的一个运转。

    而且避免不断新建线程的开销。可以尽可能的少开启线程,并且进入系统的调度。

    如果不用线程池这个来了1000个任务开启1000个线程,然后关闭掉,下次又有任务的又新建。。这个开销明显线程池避免了。

    而且当有太多的线程后(根据硬件),系统忙于线程的调度导致实际上线程的执行效率下降。线程池可以保证一个合理的线程数量而让系统维持调度线程的低开销。

    线程池还有其他的一些种类。我这只是讲讲线程池的一个是实现的思路,简单的原理。想要详细了解还得自己升入学习。

    在android系统中这种忽然上1000的任务并发现实中虽然不太可能。。。但是还是推荐用AsyncTask的包含线程池的实现 去做多线程的任务。

    分析:AsyncTask源码

    1. public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
    这是有一个static的线程池对象。这个进程内共用的线程池。(不知道是不是所有android程序都共用这个线程池。。求大神现身。)

    01. public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    02. return executeOnExecutor(sDefaultExecutor, params);
    03. }
    04. public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
    05. Params... params) {
    06. if (mStatus != Status.PENDING) {
    07. switch (mStatus) {
    08. case RUNNING:
    09. throw new IllegalStateException("Cannot execute task:"
    10. " the task is already running.");
    11. case FINISHED:
    12. throw new IllegalStateException("Cannot execute task:"
    13. " the task has already been executed "
    14. "(a task can be executed only once)");
    15. }
    16. }
    17.  
    18. //状态标记为后台线程正在运行
    19. mStatus = Status.RUNNING;
    20.  
    21. //执行 用户继承的初始化操作
    22. onPreExecute();
    23.  
    24. //运行的参数放到任务中
    25. mWorker.mParams = params;
    26. //用线程池去执行
    27. exec.execute(mFuture);
    28.  
    29. return this;
    30. }

    这样子线程池执行任务mWorker

    01. mWorker = new WorkerRunnable<Params, Result>() {
    02. public Result call() throws Exception {
    03. mTaskInvoked.set(true);
    04.  
    05. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    06. //noinspection unchecked
    07. //线程池 运行这个任务。并且postResult把结果发出去
    08. return postResult(doInBackground(mParams));
    09. }
    10. };

    可以看到这个任务执行了doInBackground()方法。这个任务是通过线程池在多线程的环境下执行的。也就是说doInBackground()也是多线程执行的。

    1. private Result postResult(Result result) {
    2. @SuppressWarnings("unchecked")
    3. Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
    4. new AsyncTaskResult<Result>(this, result));
    5. message.sendToTarget();
    6. return result;
    7. }

    通过Hanlder + message把结果result传递出去。

    01. private static class InternalHandler extends Handler {
    02. @SuppressWarnings({"unchecked""RawUseOfParameterizedType"})
    03. @Override
    04. public void handleMessage(Message msg) {
    05. AsyncTaskResult result = (AsyncTaskResult) msg.obj;
    06. switch (msg.what) {
    07. case MESSAGE_POST_RESULT:
    08. // There is only one result
    09. result.mTask.finish(result.mData[0]);//处理结果
    10. break;
    11. case MESSAGE_POST_PROGRESS:
    12. result.mTask.onProgressUpdate(result.mData);//处理中间数据
    13. break;
    14. }
    15. }
    16. }
    17. private void finish(Result result) {
    18. if (isCancelled()) {
    19. onCancelled(result);
    20. else {
    21. onPostExecute(result);
    22. }
    23. mStatus = Status.FINISHED;
    24. }



    这个hanlder处理接收到的消息。

    可以看到调用了finish() 并在finish中调用onPostExecute 让用户去使用结果。

    最后总结Java的多线程是Thread实现,跟runnable没有太大关系。

    android中因为需要多线程交换数据出现了handler+message+thread实现多线程数据通信。就hanlder本身而言并不是实现多线程。

    因为handler+message+thread手写比较负载,所以android提供AsyncTask去实现多线程,并且拥有多线程数据同步的能力。

    AsyncTask的本质就是handler+message+thread(线程池)的实现。因此要是简单的使用多线程,android中使用asyncTask就足够了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值