进程:Android运转的最小单位,通常情况,一个Android应用拥有一个进程;特殊需求,如需单独开启新进程,可以通过android:process 属性开启新的进程;该属性可以声明到activity中,创建activity时默认开启单独的进程;
线程:进程运行的最小单位;一个Application对应一个主线程,负责主要的UI操作;为防止出现ANR(Application not response),通常不在UI线程中进行耗时操作。网络请求、数据库处理、数据处理等操作,通常开辟新线程完成,也叫子线程。
线程创建的两种方式:
继承Thread类;实现Runnable接口;
将待处理的代码逻辑置于run()方法中,通过start()方法执行子线程中的代码逻辑。
当多个子线程频繁使用时,会不断重复创建、运行、销毁线程,对性能造成一定的影响。合理利用线程池有以下优点:
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
1、使用未封装的ThreadPoolExecutor
选取参数最多的构造方法进行解读:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueueworkQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
以下参数解读均参考https://blog.csdn.net/l540675759/article/details/62230562 一文:
corePoolSize--核心线程数。
默认情况下,核心线程数会在线程中一直存活,即使它们处于闲置状态。
但将ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,那么核心线程就会存在超时策略,这个时间间隔由keepAliveTime所决定,当等待时间超过keepAliveTime所指定的时长后,核心线程就会被停止。
maximumPoolSize --线程池所能容纳的最大线程数。
当活动线程数达到这个数值后,后续的新任务将会被阻塞。
keepAliveTime --非核心线程corePool闲置的超时时长。
超过这个时长,非核心线程就会被回收;当ThreadPoolExector的allowCoreThreadTimeOut属性设置为True时,keepAliveTime同样会作用于核心线程。
unit --用于指定keepAliveTime参数的时间单位。
这是一个枚举,常用的有TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)以及TimeUnit.MINUTES(分钟)等。
TimeUnit.NANOSECONDS 纳秒
TimeUnit.MICROSECONDS 微秒
TimeUnit.MILLISECONDS 毫秒
TimeUnit.SECONDS 秒
TimeUnit.MINUTES 分钟
TimeUnit.HOURS 小时
TimeUnit.DAYS 天
workQueue --线程池中的任务队列。
通过线程池execute方法提交的Runnable对象会存储在这个参数中。
这个任务队列是BlockQueue类型,属于阻塞队列,就是当队列为空的时候,此时因为无任务可以被取出,该操作会被阻塞,等待任务加入队列中不为空的时候,才能进行取出操作;同理,在满队列的时候,添加操作同样会被阻塞。
threadFactory --线程工厂。
为线程池提供创建新线程的功能。ThreadFactory是一个接口,它只有一个方法,newThread(Runnable r),用来创建线程。
2、使用封装后的 ExecutorService
JDK提供了完整的ExecutorService线程池,通过Executors创建符合需求的线程池;
由ExecutorService对线程池进行管理;
Executor将runnable对象execute()到容器中进行代码执行。
类图及解读如下,取自https://www.cnblogs.com/whx20100101/p/9862392.html:
类图解读:
①ExecutorService 接口继承了Executor 接口,是Executor 的子接口;
②Executor接口中定义了execute()方法,用来接收一个Runnable接口的对象,
而ExecutorService接口中定义的submit()方法可以接收Runnable和Callable接口对象;
③Executor接口中execute()方法不返回任何结果,而ExecutorService接口中submit()方法可以通过一个 Future 对象返回运算结果。
④Executor和ExecutorService除了允许客户端提交一个任务,ExecutorService 还提供用来控制线程池的方法。 比如:调用 shutDown() 方法终止线程池。
⑤Executors 类提供工厂方法用来创建不同类型的线程池。比如:
newCachedThreadPool()创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newSingleThreadExecutor() 创建一个只有一个线程的线程池,
newFixedThreadPool(int numOfThreads)来创建固定线程数的线程池,
newScheduledThreadPool(int corePoolSize) 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
1、newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
适用范围:
①当整个线程都处于闲置状态时,线程池中的线程都会超时而被停止,这时候的CacheThreadPool几乎不占任何系统资源的;
②执行很多短期异步的小程序或者负载较轻的服务器
2、FixedThreadPool
一种数量固定的线程池,当线程处于空闲的时候,并不会被回收,除非线程池被关闭;当所有的线程都处于活动状态时,新任务都会处于等待状态,直到有线程空闲出来。
由于FixedThreadPool中只有核心线程并且这些核心线程不会被回收,这意味着它能够更加快速地响应外界的请求;通过构造方法可以看出,FixedThreadPool只有核心线程,并且超时时间为0(即无超时时间),所以不会被回收.
适用范围:执行长期的任务,性能会好很多
3、newScheduledThreadPool
创建一个固定大小的线程池,线程池内线程存活时间无限制,线程池可以支持定时及周期性任务执行,如果所有线程均处于繁忙状态,对于新任务会进入DelayedWorkQueue队列中,这是一种按照超时时间排序的队列结构
适用范围:主要用于执行定时任务和具有固定周期的重复任务。
4、SingleThreadExecutor
创建只有一个线程的线程池,且线程的存活时间是无限的;当该线程正繁忙时,对于新任务会进入阻塞队列中(无界的阻塞队列)
适用范围:一个任务一个任务执行的场景
线程池任务执行流程:
取自:https://www.cnblogs.com/sachen/p/7401959.html