全方位解析

您所在的位置:网站首页 安卓线程池最多几个核心 全方位解析

全方位解析

2024-07-16 05:58| 来源: 网络整理| 查看: 265

笔记文章,没有废话,句句关键

线程池的优点重用线程池里的线程,避免创建和销毁线程所带来的性能开销有效控制最大并发数,避免造成线程间抢占系统资源而造成阻塞提高线程可管理性,可以统一进行分配,调优和监控的能力Android中的线程池

复用Java中的Executor接口,具体实现类为ThreadPoolExecutor,它有以下几个参数:

参数

说明

注释

corePoolSize

线程池中核心线程数量

一直存活,即使处于闲置状态

maximumPoolSize

最大能创建的线程数量(非核心线程,包含核心线程个数)

达到这个值后,后续任务会阻塞

keepAliveTime

非核心线程最大存活时间

当设置allowCoreThreadTimeOut=true 同样会做用于核心线程,但通常不会这么做

unit

keepAliveTime的时间单位

TimeUnit中的枚举(时间单位)

workQueue

等待队列。execute 方法提交的Runnable存储在其中

如果线程池中的线程数量大于等于corePoolSize的时候,把该任务放入等待队列

threadFactory

线程创建工程厂(用来创建线程的)

默认使用Executors.defaultThreadFactory() 来创建线程,线程具有相同的NORM_PRIORITY优先级并且是非守护线程

handler

线程池的饱和拒绝策略(不常用)

阻塞队列已且没有空闲的线程,此时继续提交任务,就需要采取一种策略处理该任务,默认会抛出异常

常用与关键方法void execute(Runnable run)//提交任务,交由线程池调度void shutdown()//关闭线程池,等待任务执行完成void shutdownNow()//关闭线程池,不等待任务执行完成int getTaskCount()//返回线程池找中所有任务的数量 (已完成的任务+阻塞队列中的任务) int getCompletedTaskCount()//返回线程池中已执行完成的任务数量 (已完成的任务) int getPoolSize()//返回线程池中已创建线程数量int getActiveCount()//返回当前正在运行的线程数量void terminated() 线程池终止时执行的策略线程池的运行状态

线程存在运行状态,如下:

状态

说明

NEW

初始状态,线程被新建,还没调用start方法

RUNNABLE

运行状态,把"运行中"和"就绪"统称为运行状态

BLOCKED

阻塞状态,表示线程阻塞于锁

WAITING

等待状态,需要其他线程通知唤醒

TIME_WAITING

超时等待状态,表示可以在指定的时间超时后自行返回

TERMINATED

终止状态,表示当前线程已经执行完毕

在这里插入图片描述

根据线程的运行状态思想,我们来展开线程池的运行状态:

状态

说明

RUNNABLE

表示当前线程池,存在正在运行的线程

SHUTDOWN

关闭线程池,不在执行新的任务,但会执行完线程池正在运行的任务,和添加到队列中的任务,对应shutDown()方法

STOP

立即关闭线程池,打断正在运行的任务,且不再处理等待队列中已添加的任务,对应shutDownNow()方法

TIDYING

shutDown() / shutDownNow()后进入此状态,表示队列和线程池为空,之后进入TERMINATED状态

TERMINATED

终止状态,表示当前线程已经执行完毕,并调用 terminated() 通知外界

在这里插入图片描述

安卓中常用的四种线程池

Executors.newFixedThreadPool()

代码语言:javascript复制public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }线程数量固定的线程池核心线程与非核心线程数量相等,意味着只有核心线程。 keepAliveTime = 0L,即使线程池中的线程空闲,也不会被回收。除非调用shutDown()或shutDownNow()去关闭线程池。可以更快响应外界的请求,且任务阻塞队列为无边界队列(LinkedBlockingQueue()链表结构的阻塞队列),意味着任务可以无限加入线程池

Executors.newScheduledThreadPool()

代码语言:javascript复制 public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 10L, MILLISECONDS, new DelayedWorkQueue()); }核心线程数量固定,非核心线程是无限的,但非核心线程存活时间非常短(10毫秒),闲置后会被回收适合执行定时任务和固定周期的重复任务DelayedWorkQueue()优先级队列(堆结构),会根据定时/延时时间进行排序,延时少,先执行

Executors.newSingleThreadExecutor() 常用

代码语言:javascript复制 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }核心线程数为1的线程池。确保所有任务在同一线程执行,因此不用考虑线程同步问题 阻塞队列是无界的,可以一直接收任务 、

Executors.newCachedThreadPool()

代码语言:javascript复制 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }没有核心线程,非核心线程无限,但执行完任务后,线程存活60秒SynchronousQueue() 是个特殊的队列,可以理解为无法存储元素的队列,因此线程池接收到任务就会创建线程去执行。当整个线程都处于空闲状态,60秒后,线程池中的线程都会因超时而被停止,不占用系统资源。根据以上两点,此线程池适合执行耗时较少但频繁的任务执行线程池源码分析

在分析源码前,先把线程池的工作流程图放出来。这样再去阅读源码会更加深刻

在这里插入图片描述

阅读源码的目的:

了解线程池如何复用如何巧妙的使用线程池,根据需求去自定义线程池,以达到暂停/恢复,任务具有优先级,监控,分配,调优等学习线程池优秀的设计思想面试吹牛逼

源码分析

分析源码前看下ThreadPoolExecutor类的头注释:

代码语言:javascript复制public class ThreadPoolExecutor extends AbstractExecutorService { /** * The main pool control state, ctl, is an atomic integer packing * two conceptual fields * workerCount, indicating the effective number of threads * runState, indicating whether running, shutting down etc * * In order to pack them into one int, we limit workerCount to * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2 * billion) otherwise representable. If this is ever an issue in * the future, the variable can be changed to be an AtomicLong, * and the shift/mask constants below adjusted. But until the need * arises, this code is a bit faster and simpler using an int. * * The workerCount is the number of workers that have been * permitted to start and not permitted to stop. The value may be * transiently different from the actual number of live threads, * for example when a ThreadFactory fails to create a thread when * asked, and when exiting threads are still performing * bookkeeping before terminating. The user-visible pool size is * reported as the current size of the workers set. * * The runState provides the main lifecycle control, taking on values: * * RUNNING: Accept new tasks and process queued tasks * SHUTDOWN: Don't accept new tasks, but process queued tasks * STOP: Don't accept new tasks, don't process queued tasks, * and interrupt in-progress tasks * TIDYING: All tasks have terminated, workerCount is zero, * the thread transitioning to state TIDYING * will run the terminated() hook method * TERMINATED: terminated() has completed * * The numerical order among these values matters, to allow * ordered comparisons. The runState monotonically increases over * time, but need not hit each state. The transitions are: * * RUNNING -> SHUTDOWN * On invocation of shutdown(), perhaps implicitly in finalize() * (RUNNING or SHUTDOWN) -> STOP * On invocation of shutdownNow() * SHUTDOWN -> TIDYING * When both queue and pool are empty * STOP -> TIDYING * When pool is empty * TIDYING -> TERMINATED * When the terminated() hook method has completed * * Threads waiting in awaitTermination() will return when the * state reaches TERMINATED. * * Detecting the transition from SHUTDOWN to TIDYING is less * straightforward than you'd like because the queue may become * empty after non-empty and vice versa during SHUTDOWN state, but * we can only terminate if, after seeing that it is empty, we see * that workerCount is 0 (which sometimes entails a recheck -- see * below). */

这里面有几段比较重要 :

代码语言:javascript复制 * The main pool control state, ctl, is an atomic integer packing * two conceptual fields * workerCount, indicating the effective number of threads * runState, indicating whether running, shutting down etc * * In order to pack them into one int, we limit workerCount to * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2 * billion) otherwise representable. If this is ever an issue in * the future, the variable can be changed to be an AtomicLong, * and the shift/mask constants below adjusted. But until the need * arises, this code is a bit faster and simpler using an int.

线程池控制状态:clt是一个int类型的原子数,它表示两个概念,workerCount表示有效线程,笼统来讲,相当于线程池运行的线程个数,runState,表示线程池运行的状态,如RUNNING SHUTDOWN等等。 将这两个字段打包成一个int,int为4字节,有32位,后29位表示线程池的数量,最大可为5个亿,如果不够可以使用AtomicLong代替。当然,运行线程池根本达不到这个数量。

代码语言:javascript复制 * RUNNING: Accept new tasks and process queued tasks * SHUTDOWN: Don't accept new tasks, but process queued tasks * STOP: Don't accept new tasks, don't process queued tasks, * and interrupt in-progress tasks * TIDYING: All tasks have terminated, workerCount is zero, * the thread transitioning to state TIDYING * will run the terminated() hook method * TERMINATED: terminated() has completed

五种状态的含义,上面提到过。

代码语言:javascript复制 * RUNNING -> SHUTDOWN * On invocation of shutdown(), perhaps implicitly in finalize() * (RUNNING or SHUTDOWN) -> STOP * On invocation of shutdownNow() * SHUTDOWN -> TIDYING * When both queue and pool are empty * STOP -> TIDYING * When pool is empty * TIDYING -> TERMINATED * When the terminated() hook method has completed

线程池状态间的变化。等于上面我们画的图:

在这里插入图片描述

结论:阅读源码可以适当看下类头说明,尤其是Android源码的类头。可以帮我们更好的理解源码

从线程池入口进入,理解前面提到ctl是什么?

代码语言:javascript复制 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3