Android 线层池解析


       为什么引入线层池概念?
如果短时间内新建大量的线层,因为线程的创建与销毁的资源开销是非常大的,大量的子线程会分享主线程的系统资源,从而会使主线程因资源受限而导致应用性能降低。用线程池去管理这堆线层,统一的分配,调优和监控。它是为提升APP性能而存在的。

1.Java通过Executors提供四种线程池:

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

示例:

ExecutorService executor = Executors.newFixedThreadPool(5);
        for(inti = 0; i < 20; i++) {
            Runnable worker = newWorkerThread(""+ i);
            executor.execute(worker);
          }
        executor.shutdown();
        while(!executor.isTerminated()) {
        }

根据newFixedThreadPool 的特性,上述在线程池会5个接5个执行。

2.Executors 类使用 ExecutorService 提供的ThreadPoolExecutor参数解析

ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,ThreadFactory,handler)

共六个参数:

corePoolSize: 线层池的基本大小。

maximumPoolSize: 线程池允许创建的最大线程数,当runnableTaskQueue(任务队列)满了的时候,线层池大小会超出corePoolSize,达到最大值。

keepAliveTime线程活动保持时间,线程池的工作线程空闲后,保持存活的时间。

TimeUnit:  线程活动保持时间的单位可选的单位,天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

RunnableTaskQueue: 任务队列 用于保存等待执行的任务的阻塞队列。

ThreadFactory:  线层工厂 给线程命名、是否为用户线程等等属性

RejectedExecutionHandler:   当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。

示例:
          
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(5,10,10, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(5),threadFactory,rejectedExecutionHandler);
        for (int i=1;i<=20;i++) {
            Runnable runnable=new WorkThread(threadPoolExecutor,i*2000,i);
            threadPoolExecutor.execute(runnable);
        }
        threadPoolExecutor.shutdown();
    }

    RejectedExecutionHandler rejectedExecutionHandler=new RejectedExecutionHandler(){

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            Log.e("RejectedHandler","转移到:RejectedExecutionHandler"+r.toString());
        }
    };

public class WorkThread implements Runnable {
    private int i;
    private ThreadPoolExecutor threadPoolExecutor;
    private int delay;
    public WorkThread(int i){
        this.i=i;
    }
    public WorkThread(ThreadPoolExecutor threadPoolExecutor,int delay,int i){
        this.threadPoolExecutor=threadPoolExecutor;
        this.delay=delay;
        this.i=i;
    }

    @Override
    public void run() {
        try {
            Log.e("WorkThread", "在执行第" + i + "线程");
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}


  
  
Logcat:


    示例中,任务队列大小是5,只会存储5个阻塞线程,线程到达10个后,任务队列不再存储线程,线程池开始超出容量,线程数到达20个时达到maximumPoolSize,然后就往rejectedExecutionHandler转移。

             如上图所示:ArrayBlockingQueue 是先进先出的的原则,11-15个线程是超出线层池基本容量后达到最大容量的。6-10是阻塞放在任务列的,6-10线程会在后面执行。其中16-20线程转移到RejectedExecutionHandler 处理。

3.线程池的关闭方法

            shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务;
            shutdownNow():立即终止线程池,并尝试打断正在执行的任务(测试过,线程里的任务还是会执行下去的),并且清空任务缓存队列,返回尚未执行的任务。重新使用必须先初始化,否则会报错。

            在Activity关闭的时候要关闭线程池,不然很容易造成内存泄露。 

4.AsyncTask内部的线程池封装学习

 

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
    private final AtomicInteger mCount = new AtomicInteger(1);

    public Thread newThread(Runnable r) {
        return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
    }
};

private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

/**
 * An {@link Executor} that can be used to execute tasks in parallel.
 */
public static final Executor THREAD_POOL_EXECUTOR
       = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
       这个 轻量级的抽象异步类封装了静态的线程池,设置了基本大小是可用处理器数量加1(CUP_COUNT+1),最大数量是CUP数的两倍。据说这个是根据线程的计算公式: 线程数=CPU核心数/(1-阻塞系数),最佳线程个数一般在N和N+1之间选择。(度娘了一下=-=)。线程池并发太大,CPU都HOLD不住了。。。

      然后任务队列使用了LinkedBlockingQueue 最大为128的一个基于链表结构的阻塞队列,此队列按 FIFO (先进先出) 排序元素。

      最后看看ThreadFactory 线程工厂这个接口。AtomicInteger 是一种线程安全的加减操作接口,保证线程安全有序的给线程命名咯。

      当然这只是一部分,AsyncTask内部还有很多东西值得借鉴学习。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值