Android为啥阿里Android开发手册中,线程池不建议使用Executors去创建?

Posted 码农搬砖_2020

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android为啥阿里Android开发手册中,线程池不建议使用Executors去创建?相关的知识,希望对你有一定的参考价值。

Executors 返回的线程池对象的弊端如下:

  1. FixedThreadPool 和 SingleThreadPool : 允 许 的 请 求 队 列 长 度 为
    Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM;
  2. CachedThreadPool 和 ScheduledThreadPool : 允 许 的 创 建 线 程 数 量 为
    Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

正例:

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors(); 
int KEEP_ALIVE_TIME = 1;
TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>(); 
ExecutorService executorService = new ThreadPoolExecutor(NUMBER_OF_CORES, NUMBER_OF_CORES*2, KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT,
taskQueue, new BackgroundThreadFactory(), new DefaultRejectedExecutionHandler());

反例:


ExecutorService cachedThreadPool = Executors.newCachedThreadPool();


线程池知识科普

(1)ThreadPoolExecutor

/**
* 本质上来说 线程池的执行逻辑其实真的很简单:
* 如果当前线程池的线程个数小于CORE_POOL_SIZE 那么有任务到来的时候 就直接创建一个线程 执行这个任务
* 如果当前线程池的线程个数已经到了CORE_POOL_SIZE这个极限,那么新来的任务就会被放到workQueue中
* 如果workQueue里面的任务已满,且MAXIMUM_POOL_SIZE这个值大于CORE_POOL_SIZE,那么此时线程池会继续创建线程执行任务
* 如果workQueue满了,且线程池的线程数量也已经达到了MAXIMUM_POOL_SIZE 那么就会把任务丢给rejectedExecutionHandler 来处理
* 当线程池中的线程超过了CORE_POOL_SIZE的哪些线程 如果空闲时间到了KEEP_ALIVE_TIME 那么就会自动销毁
* 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭

 */
    
ExecutorService executorService = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.MILLISECONDS, workQueue, threadFactory, rejectedExecutionHandler);

(2)线程队列workQueue

队列就分为两种,一种是有界队列,一种是无界队列。他俩最大的区别是:

无界队列可以一直往里面丢任务,而有界队列当发现到了队列大小极限以后就直接拒绝新任务的到来了。

这里面的坑就是 无界队列你无限往里面丢任务,如果任务执行的慢 有可能任务太多 就oom了。

  1. 直接提交队列:使用的是SynchronousQueue类实现的队列。

提交到这个队列中的任务不会被真实的保存,而是立刻将新任务提交个线程执行,如果没有空闲的线程,就会创建新的线程,如果线程数量达到线程池的最大线程数maximumPoolSize,那么就会执行拒绝策略,任务执行被拒绝。

  1. 有界的任务队列:

使用的是ArrayBlockingQueue类实现的队列,按照“先进先出”算法处理任务,它的构造函数是:
public ArrayBlockingQueue(int capacity)

使用它必须设置一个最大容量参数,使用有界的任务队列的线程池,当有任务提交后,如果当前线程池中的线程数小于corePoolSize,就会创建新的线程执行任务,如果任务提交后,当前线程池内线程数大于corePoolSize,就会把任务先放到有界任务队列中,若队列放满后,再创建新线程执行任务,但总的线程数不会超过最大值maximumPoolSize。

  1. 无界的任务队列:

使用的是LinkedBlockingQueue类实现,不需要事先制定大小,也是按照“先进先出”算法处理任务。无界队列很好理解,就是和有界队列相反,使用无界队列的线程池,当有新任务提交时,如果线程池里有空闲线程,就分配线程立刻执行任务,否则就把任务放到无界任务队列中等待,如果线程池中一直没有空闲线程,但是新的任务又一直不停的提交上来,那么这些任务全部会被挂到等待队列中,一直到内存全部消耗完。

  1. 优先任务队列:

使用的是PriorityBlockingQueue类实现,它根据任务的优先级顺序执行任务,是一个无界队列,它没有限制,在内存允许的情况下可以无限添加元素;它又是具有优先级的队列,是通过构造函数传入的对象来判断,传入的对象必须实现comparable接口。

public class Person implements Comparable<Person>
	private int id;
	private String name;
	public int getId() 
		return id;
	
	public void setId(int id) 
		this.id = id;
	
	public String getName() 
		return name;
	
	public void setName(String name) 
		this.name = name;
	
	public Person(int id, String name) 
		super();
		this.id = id;
		this.name = name;
	
	public Person() 
	
	@Override
	public String toString() 
		return this.id + ":" + this.name;
	
	@Override
	public int compareTo(Person person) 
		return this.id > person.getId() ? 1 : ( this.id < person.getId() ? -1 :0);
	

	public static void main(String[] args) throws InterruptedException 
		PriorityBlockingQueue<Person> pbq = new PriorityBlockingQueue<>();
		pbq.add(new Person(3,"person3"));
		pbq.add(new Person(2,"person2"));
		pbq.add(new Person(1,"person1"));
	

以上是关于Android为啥阿里Android开发手册中,线程池不建议使用Executors去创建?的主要内容,如果未能解决你的问题,请参考以下文章

火速下载!《阿里巴巴Android开发手册》重磅发布!

重磅开源!《阿里巴巴Android开发手册》抢鲜下载!

Flutter阿里巴巴Android开发手册机器学习

阿里程序员的2019Android年终盘点,必备技能知识点,程序员必须收藏

阿里内部人士分享的高级Android 组件化实战手册,如何维护一个巨大的Android项目呢?

速看!阿里大佬熬夜整理的 Android Framework 内部学习手册,开放下载!