美文网首页Android技术进阶Android技术知识Android开发
Android开发——ThreadPoolExecutor与自定

Android开发——ThreadPoolExecutor与自定

作者: 谁动了我的代码 | 来源:发表于2022-11-21 21:02 被阅读0次

    一、概述

    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);
            }
        }
    }
    

    以上就是Android开发中ThreadPoolExecutor与自定义线程池;进阶Android的核心技术,可以参考《Android核心技术》这个技术文档,查看免费获取方法。

    文末

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

    相关文章

      网友评论

        本文标题:Android开发——ThreadPoolExecutor与自定

        本文链接:https://www.haomeiwen.com/subject/puowxdtx.html