美文网首页
Android线程相关

Android线程相关

作者: Vinson武 | 来源:发表于2020-04-16 15:29 被阅读0次

==进程和线程==

  • 进程:进程是资源分配的基本单位。进程控制块 (Process Control Block, PCB) 描述进程的基本信息和运行状态,所谓的创建进程和撤销进程,都是指对 PCB 的操作。
  • 线程:线程是独立调度的基本单位。一个进程中可以有多个线程,它们共享进程资源。

区别

  • 拥有资源:进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。
  • 调度:线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
  • 系统开销:由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,开销很大。而线程切换时只需保存和设置少量寄存器内容,开销很小。
  • 通信方面:线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC。

线程池的好处? 四种线程池的使用场景,线程池的几个参数的理解?

  • 使用线程池的好处是==减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题==。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或则“过度切换”的问题,归纳总结就是
  1. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
  2. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  3. 提供定时执行、定期执行、单线程、并发数控制等功能。
  • ==Android中的线程池都是直接或间接通过配置ThreadPoolExecutor来实现不同特性的线程池==.Android中最常见的类具有不同特性的线程池分别为:
  1. ==newCachedThreadPool==:只有非核心线程,最大线程数非常大,所有线程都活动时会为新任务创建新线程,否则会利用空闲线程 (60s空闲时间,过了就会被回收,所以线程池中有0个线程的可能 )来处理任务.

优点:任何任务都会被立即执行(任务队列SynchronousQuue相当于一个空集合);比较适合执行大量的耗时较少的任务.

  1. ==newFixedThreadPool==:只有核心线程,并且数量固定的,所有线程都活动时,因为队列没有限制大小,新任务会等待执行,当线程池空闲时不会释放工作线程,还会占用一定的系统资源。

优点:更快的响应外界请求

  1. ==newScheduledThreadPool==:核心线程数固定,非核心线程(闲着没活干会被立即回收数)没有限制.

优点:执行定时任务以及有固定周期的重复任务

  1. ==newSingleThreadExecutor==:只有一个核心线程,确保所有的任务都在同一线程中按序完成

优点:不需要处理线程同步的问题

ThreadPoolExecutor的工作策略 ?

ThreadPoolExecutor执行任务时会遵循如下规则

  1. 如果线程池中的线程数量未达到核心线程的数量,那么会直接启动一个核心线程来执行任务。
  2. 如果线程池中的线程数量已经达到或则超过核心线程的数量,那么任务会被插入任务队列中排队等待执行。
  3. 如果在第2点无法将任务插入到任务队列中,这往往是由于任务队列已满,这个时候如果在线程数量未达到线程池规定的最大值,那么会立刻启动一个非核心线程来执行任务。
  4. 如果第3点中线程数量已经达到线程池规定的最大值,那么就拒绝执行此任务,ThreadPoolExecutor会调用RejectedExecutionHandler的rejectedExecution方法来通知调用者。

Android中还了解哪些方便线程切换的类?

  • ==AsyncTask==:底层封装了线程池和Handler,便于执行后台任务以及在子线程中进行UI操作。
  • ==HandlerThread==:一种具有消息循环的线程,其内部可使用Handler。
  • ==IntentService==:是一种异步、会自动停止的服务,内部采用HandlerThread。

AsyncTask的原理和问题

原理:

  • AsyncTask中有两个线程池(SerialExecutor和THREAD_POOL_EXECUTOR)和一个Handler(InternalHandler),其中==线程池SerialExecutor用于任务的排队,而线程池THREAD_POOL_EXECUTOR用于真正地执行任务,InternalHandler用于将执行环境从线程池切换到主线程。==
  • 注意:sHandler是一个静态的Handler对象,为了能够将执行环境切换到主线程,这就要求sHandler这个对象必须在主线程创建。由于静态成员会在加载类的时候进行初始化,==因此这就变相要求AsyncTask的类必须在主线程中加载==,否则同一个进程中的AsyncTask都将无法正常工作。

问题:

  • 生命周期:AsynTask会一直执行,直到doInBackground()方法执行完毕,然后,如果cancel(boolean)被调用,那么onCancelled(Result result)方法会被执行;否则,执行onPostExecute(Result result)方法。==如果我们的Activity销毁之前,没有取消AsyncTask,这有可能让我们的应用崩溃==(crash)。因为它想要处理的view已经不存在了。所以,我们是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确的取消。
  • ==内存泄漏==:如果AsyncTask被声明为Activity的非静态内部类,那么AsyncTask会保留一个对Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄漏。(所以应将AsyncTask声明为静态内部类)
  • ==结果丢失==:屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

IntentService有什么用 ?

  • IntentService可用于执行后台耗时的任务,当任务执行完成后会自动停止,同时由于IntentService是服务的原因,不同于普通Service,IntentService可自动创建子线程来执行任务,这导致它的优先级比单纯的线程要高,不容易被系统杀死,所以IntentService比较适合执行一些高优先级的后台任务。

直接在Activity中创建一个thread跟在service中创建一个thread之间的区别?

在Activity中被创建:该Thread的就是为这个Activity服务的,完成这个特定的Activity交代的任务,主动通知该Activity一些消息和事件,==Activity销毁后,该Thread也没有存活的意义了。==
在Service中被创建:这是保证最长生命周期的Thread的唯一方式,==只要整个Service不退出,Thread就可以一直在后台执行==,一般在Service的onCreate()中创建,在onDestroy()中销毁。所以,在Service中创建的Thread,适合长期执行一些独立于APP的后台任务,比较常见的就是:在Service中保持与服务器端的长连接。

Handler、Thread和HandlerThread的差别?

  • Handler:在android中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯。
  • Thread:Java进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。
  • HandlerThread:一个继承自Thread的类HandlerThread,Android中没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类,这个类对Java的Thread做了很多便利的封装。==HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它在内部直接实现了Looper的实现,这是Handler消息机制必不可少的。有了自己的looper,可以让我们在自己的线程中分发和处理消息==。如果不用HandlerThread的话,需要手动去调用Looper.prepare()和Looper.loop()这些方法。

ThreadLocal的原理

==ThreadLocal是一个关于创建线程局部变量的类==。使用场景如下所示:

  • 实现单个线程单例以及单个线程上下文信息存储,比如交易id等。

  • 实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例。 承载一些线程相关的数据,避免在方法中来回传递参数。

  • 当需要使用多线程时,有个变量恰巧不需要共享,此时就不必使用synchronized这么麻烦的关键字来锁住,每个线程都相当于在堆内存中开辟一个空间,线程中带有对共享变量的缓冲区,通过缓冲区将堆内存中的共享变量进行读取和操作,==ThreadLocal相当于线程内的内存,一个局部变量。每次可以对线程自身的数据读取和操作,并不需要通过缓冲区与 主内存中的变量进行交互==。并不会像synchronized那样修改主内存的数据,再将主内存的数据复制到线程内的工作内存。==ThreadLocal可以让线程独占资源,存储于线程内部,避免线程堵塞造成CPU吞吐下降==。

  • 在每个Thread中包含一个ThreadLocalMap,ThreadLocalMap的key是ThreadLocal的对象,value是独享数据。

多线程是否一定会高效(优缺点)

  • 多线程的优点:
  1. 方便高效的内存共享——多进程下内存共享比较不便,且会抵消掉多进程编程的好处
  2. 较轻的上下文切换开销不用切换地址空间,不用更改CR3寄存器,不用清空TLB
  3. 线程上的任务执行完后自动销毁
  • 多线程的缺点:
  1. 开启线程需要占用一定的内存空间(默认情况下,每一个线程都占512KB)
  2. 如果开启大量的线程,会占用大量的内存空间,降低程序的性能
  3. 线程越多,cpu在调用线程上的开销就越大
    程序设计更加复杂,比如线程间的通信、多线程的数据共享。
  • 综上得出,多线程不一定能提高效率,在内存空间紧张的情况下反而是一种负担,因此在日常开发中,应尽量:
  1. 不要频繁创建,销毁线程,使用线程池
  2. 减少线程间同步和通信(最为关键)
  3. 避免需要频繁共享写的数据
  4. 合理安排共享数据结构,避免伪共享(false sharing)
  5. 使用非阻塞数据结构/算法
  6. 避免可能产生可伸缩性问题的系统调用(比如mmap)
  7. 避免产生大量缺页异常,尽量使用Huge Page
  8. 可以的话使用用户态轻量级线程代替内核线程

参考链接

相关文章

  • Android下多线程的实现

    Android下多线程相关 线程安全相关问题参考:java内存模型与线程 android下与多线程有关的主要有以下...

  • 笔记:Android线程和线程池

    Android线程和线程池 Android中的线程操作相关的类有 AsyncTask IntentService ...

  • 线程池创建和相关知识

    线程池创建(单例):Android线程池得要这么用 - 简书 线程池相关知识:Android开发之线程池使用总结 ...

  • Android线程相关

    ==进程和线程== 进程:进程是资源分配的基本单位。进程控制块 (Process Control Block, P...

  • Android多线程

    Android 多线程 本篇博客将涉及以下内容: 多线程概述 Thread类和Runnable接口 线程相关(线程...

  • Android多线程模式---Thread,AsyncTask,

    Android多线程 因为Android主线程用于处理界面相关事件,如果有耗时任务必须转到子线程执行。否则如果任务...

  • Android 多线程(一)

    简介 1. 线程分类 主线程(UI线程) : 处理和界面相关的事情. 子线程 : 处理耗时操作. Android中...

  • 进程、线程、多线程区别

    原文:Android面试总结:进程、线程、多线程相关总结[https://cloud.tencent.com/de...

  • Android线程

    Android线程概述 线程分为主线程和子线程,主线程主要处理和界面相关的事情,子线程则往往用于处理耗时操作。线程...

  • Android线程

    1、引言 在Android中,几乎完全采用了Java的线程机制,由于Android的特性,主线程只处理和界面相关的...

网友评论

      本文标题:Android线程相关

      本文链接:https://www.haomeiwen.com/subject/qborvhtx.html