Android 线程

作者 : 开心源码 本文共4131个字,预计阅读时间需要11分钟 发布时间: 2022-05-13 共224人阅读

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

使用线程池的好处在于,是可以减少在创立和销毁线程上所花的时间,以及系统资源的开销,处理资源不足的问题。假如不使用线程池,有可能造成系统创立大量同类线程而导致消耗完内存或者者“过度切换“的问题,归纳总结就是:

  • 重用存在的线程,减少对象创立、消亡的开销,性能佳。
  • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  • 提供定时执行、定期执行、单线程、并发数控制等功能。

Andorid中的线程池都是直接或者间接通过配置ThreeadPoolExecutor来实现不同特性线程池。Android中最常见的类具备不同特性的线程池分别为:

  • newCachedThreadPool:只有非核心线程,最大线程数非常大,所有线程都活动时,会为新任务创立新线程,否则会利用空闲线程(60s空闲时间,过了就会被回收,所以线程池中有0个线程的可能)来解决任务。
    • 优点:任何任务都会被立即执行(任务队列SynchonousQue相当于一个空集合);比较适合执行大量的耗时较少的任务。
  • newFixedThreadPool:只有核心线程,并且数量固定的,所有线程都活动时,由于队列没有限制大小,新任务会等待执行,当线程池空闲时,不会释放工作线程,还会占用肯定的系统资源。
    • 优点:更快的响应外界请求
  • newScheduledThreadPool:核心线程数固定,非核心线程(闲置没活干会被立即回收)没有限制。
    • 优点:执行定时任务以及固定周期的重复任务
      newSingleThreadExecutor:
      只有一个核心线程,确保所有任务都在同一线程中按序完成
    • 优点:不需要解决线程同步的问题

通过源码可以理解到上面四种线程池实际还是利用ThreadPoolExecutor类实现的:

2、Android中还理解哪些方便线程切换的类?

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

3、讲讲AsyncTask的原理

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

4、IntentService有什么用?

IntentService可用于执行后端耗时的任务,当任务执行完成后会自动中止,同时因为IntentService是服务的起因,不同于普通Service,IntentService可自动创立子线程来执行任务,这导致它的优先级比单纯的线程要高,不容易被系统杀死,所以IntentService比较适合执行少量高优先级的后端任务。

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

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

6、ThreadPollExecutor的工作策略?

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

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

7、Handler、Thred和HandlerThread的差别?

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

8、ThreadLocal的原理

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

  • 实现单个线程单例以及单个线程上下文消息存储,比方交易id等。
  • 实现线程安全,非线程安全对象使用ThreadLocal之后就会变得线程安全。由于每个线程都会有一个对应的实例。承载少量线程相关的数据,避免在方法中来回传递参数。

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

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

9、多线程能否肯定会高效(优缺点)

多线程的优点

  • 方便高效的内存共享 – 多进程内存共享比较不便,且会抵消掉多进程编程的好处
  • 较轻的上下文切换开销 – 不用切换地址空间,不用更改CR3寄存器,不用清空TLB
  • 线程上的任务执行完后自动销毁

多线程的缺点:

  • 开启线程需要占用肯定的内存空间(默认情况下,每个线程都占512KB)
  • 假如开启大量的线程,会占用大量的内存空间,降低程序的性能
  • 线程越多,cpu在调用线程上的开销就越大
  • 程序设计更加复杂,比方线程间的通信、多线程的数据共享

综合得出,多线程不肯定能提高效率,在内存空间紧张的情况下反而是一种复旦,因而在日常反开发中,应尽量:

  • 不要频繁创立,销毁线程,使用线程池
  • 减少线程间同步和通信(最为关键)
  • 避免需要频繁共享写的数据
  • 正当共享数据结构,避免共享(false sharing)
  • 使用非阻塞数据结构、算法
  • 避免可能产生大量缺页异常,尽量使用Huge Page
  • 可以的话使用客户态轻量级线程代替内核线程

10、多线程中,让你做一个单例,你会怎样做

多线程中建立单例模式考虑的因素有很多,比方线程安全-推迟加载-代码安全:如防止序列化攻击,防止反射攻击()防止反射进行私有方法调用-性能因素
实现方法有多重,饿汉,懒汉(线程安全,现场非安全),多重检查(DCL),内部类,以及枚举

11、除了notify还有什么方式可以唤醒线程

  • 当一个拥有Object锁的线程调用wait()方法时,就会使当前线程加入object。wait等待队列中,并且释放当前占用的Object锁,这样其余线程就会有机会获取这个Object锁,取得Objecet锁的线程调用notify()方法,就能Object.wait等待队列中随机唤醒一个线程(该唤醒是随机的与加入的顺序无关,优先级高的被唤醒概率会高)

  • 假如调用notifyAll()方法就唤醒一律的线程。注意:调用notify()方法后并不会立即释放object锁,会等待该线程执行完毕后释放Objecet锁。

12、什么事ANR?什么情况会出现ANR?如何避免?在不看代码的情况下如何快速定位出现ANR问题所在?

  • ANR(Application Not Responding,应用无响应):当操作在一段时间内系统无法解决时,会在系统层面会弹出ANR对话框
  • 产生ANR可能是由于5s内无响应客户输入时间、10s内未结束BroadcastReceiver、20s内未结束Service
  • 想要避免ANR就不要在主线程做耗时操作,而是通过开子线程,方法比方继承Thread或者实现Runnable接口、使用AsyncTask、IntentService、HandlerThread等
说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android 线程

发表回复