Android开发—ThreadPoolExecutor与自定义线程池

一、概述

1、ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务;
2、Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。
3、先来了解其线程池管理的机制,有助于正确使用,避免错误使用导致严重故障。同时可以根据自己的需求实现自己的线程池

ThreadPoolExecutor 类

构造方法
public ThreadPoolExecutor(
    int corePoolSize,                   //核心线程数量:如果当前运行的线程数量没有达到 corePoolSize,则新建一个线程,否则加入到任务队列中
    int maximumPoolSize,                //最大线程数:当前系统最多存在的线程数
    long keepAliveTime,                 //最大空闲时间:线程空闲的最大时间,超出时间该线程会销毁;设置allowCodeThreadTimeOut(true/false),可控制核心线程是否销毁,默认false 表示允许核心线程即使超过最大线程时间也不会销毁
    TimeUnit unit,                      //时间单位: 线程空闲的最大时间的单位
    BlockingQueue<Runnable> workQueue,  //任务队列: 核心线程数量满了之后,提交的任务加入到队列中,等待核心线程数减少后再去创建线程;当任务队列已满,但没有达到最大线程数时,则新建非核心线程
    ThreadFactory threadFactory,        //线程工厂: 自定义线程的创建
    RejectedExecutionHandler handler    //饱和处理机制:当任务队列已满且达到最大线程数时,采取的措施
)   

线程池原理

线程池底层使用**堵塞式队列 BlockingQueue **。

队列遵从:先进先出,后进后出原则。
阻塞队列(BlockingQueue)和非阻塞队列(ConcurrentLinkedQueue )区别:

无界和有界队列:

ConcurrentLinkedQueue 是无界队列,不用设置长度,可以随便存放值(其实是jdk伪造的,最大长度是Integer的最大值)
BlockingQueue 是有界队列,需要设置长度。
注意:如果BlockingQueue 不设置等待时间就是非阻塞队列

存入:

非阻塞队列:如果存放超出了队列总数,添加不进去,就会丢失。
阻塞队列:如果存放超出了队列总数,进行等待,直到有队列出列,或者超时设置的等待时间)

获取:

非阻塞队列:如果为空时,返回空。
阻塞队列:如果为空时,进行等待,直到有新的队列入列,或者超过设置的等待时间

创建线程池的构造方法

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue)

  • ThreadPoolExecutor
  • 参数说明
  • 核心线程大小(corePoolSize)
  • 最大线程大小(maximumPoolSize)
  • 终止时间(keepAliveTime)
  • Unit 超时时间
  • workQueue 线程容器

自定义线程池

1、编写任务类

public class MyTask implements Runnable{
    //任务id
    private int id;
    
    public MyTask(int id){
        this.id=id;
    }
    
    @Override
    public void run() {
        String name=Thread.currentThread().getName();
        System.out.println("线程:"+name+"-->即将执行任务"+id);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程:"+name+"执行完成"+id);
    }
    
    @Override
    public String toString() {
        return "MyTask{" +
                "id=" + id +
                '}';
    }
}

2、编写线程类,用于执行任务

public class MyThread extends  Thread{

    private List<Runnable> tasks;
    
    public MyThread(String name, List<Runnable> tasks){
        super(name);
        this.tasks=tasks;
    
    }
    
    @Override
    public void run() {
        while (tasks.size() > 0){
            Runnable r= tasks.remove(0);
            r.run();
        }
    }
}

3、编写线程池类,用于管理线程的执行

public class MyThreadPool {

    private List<Runnable>  tasks = Collections.synchronizedList(new LinkedList<>());
    /**
     * 当前线程数
     */
    private int num;
    /**
     * 核心线程数
     */
    private int corePoolSize;
    /**
     * 最大线程数
     */
    private int maxSize;
    /**
     * 任务队列数
     */
    private int workSize;
    
    public MyThreadPool(int corePoolSize, int maxSize, int workSize) {
        this.corePoolSize = corePoolSize;
        this.maxSize = maxSize;
        this.workSize = workSize;
    }
    /**
     * 提交任务
     */
    public void submit(Runnable r){
    
        if (tasks.size()>=workSize && tasks.size() > maxSize){
            System.out.println("任务:"+r+"被丢弃了");
        }else{
            tasks.add(r);
            execTask(r);
        }
    }
    
    public void execTask(Runnable r){
        if (corePoolSize > num){
            new MyThread("核心线程:"+num,tasks).start();
            num++;
        }else  if(num < maxSize){
            new MyThread("非核心线程:"+num,tasks).start();
            num++;
        }else{
            System.out.println("任务:"+r+"被缓存了");
        }
    }

}


4、测试

public class Demo {
    public static void main(String[] args) {
        MyThreadPool myThreadPool = new MyThreadPool(2, 4, 20);
        for (int i =0;i< 300;i++){
            MyTask myTask = new MyTask(i);
            myThreadPool.submit(myTask);
        }
    }
}

文末

1、用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM
2、如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交。保证不抛弃一个任务
3、最大线程数一般设为2N+1最好,N是CPU核数
4、核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数
5、如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值