【Android 异步操作】线程池 ( 线程池使用示例 | 自定义线程池使用流程 | 自定义任务拒绝处理策略 | 完整代码示例 )

简介: 【Android 异步操作】线程池 ( 线程池使用示例 | 自定义线程池使用流程 | 自定义任务拒绝处理策略 | 完整代码示例 )

文章目录

一、自定义线程池使用流程

二、自定义任务拒绝处理策略

三、完整代码示例



在博客 【Android 异步操作】线程池 ( 线程池简介 | 线程池初始化方法 | 线程池种类 | AsyncTask 使用线程池示例 ) 中 , 简单介绍了 线程池 , 以及 Java 提供的四个基本线程池 , 线程池的 基本工作机制 , 如核心线程 , 非核心线程 等 ;



在博客 【Android 异步操作】线程池 ( 线程池 execute 方法源码解析 ) 中 , 讲解 线程池 ThreadPoolExecutor 的 execute 方法时 , 有两个重要的核心方法 ;


两个核心的操作 :


添加任务 : addWorker(command, true) , 第二个参数为 true 是添加核心线程任务 , 第二个参数为 false 是添加非核心线程任务 ;

拒绝任务 : reject(command)


在博客 【Android 异步操作】线程池 ( 线程池 reject 拒绝任务 | 线程池 addWorker 添加任务 ) 介绍了 addWorker 添加任务 , reject 拒绝任务 的源码细节 ;



在博客 【Android 异步操作】线程池 ( Worker 简介 | 线程池中的工作流程 runWorker | 从线程池任务队列中获取任务 getTask ) 中介绍了 工作者 Worker 的工作流程 ;




本博客中简单介绍线程池的使用示例






一、自定义线程池使用流程


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



2 . 线程池任务队列 : 指定 BlockingQueue<Runnable> 类型的线程池队列 , 同时指定队列大小 ;


 

/**
     * 线程池任务队列
     * 最多可以容纳 128 个可执行的任务
     */
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);



3 . 初始化线程池 : 调用 ThreadPoolExecutor 的 构造函数 初始化线程池 , 并对线程池进行配置 , 配置内容包括如下内容 :


核心线程数

最大线程数

非核心线程最大限制时间

闲置时间的时间单位

线程池任务队列

线程创建工厂

   

/*
            在静态代码块中初始化线程池
            在构造函数中对线程池进行配置 , 配置内容包括 :
            核心线程数
            最大线程数
            非核心线程最大限制时间
            闲置时间的时间单位
            线程池任务队列
            线程创建工厂
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;


4 . 自定义任务拒绝处理策略 : 处理任务队列已满 , 拒绝任务的情况 ;


   

THREAD_POOL_EXECUTOR.setRejectedExecutionHandler(new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
                // 自定义任务被拒绝后的处理策略
                System.out.println("任务被拒绝");
            }
        });


5 . 执行任务 : 调用线程池的 execute 方法执行任务 ;


     

THREAD_POOL_EXECUTOR.execute(
                    new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(1_000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
            );






二、自定义任务拒绝处理策略


如果执行的任务时 , 当前的线程池任务队列已满 , 此时就会拒绝任务 , 并抛出 RejectedExecutionException 异常 ;



报错信息如下 :


Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task kim.hsl.threadpool.ThreadPool$2@1f32e575 rejected from java.util.concurrent.ThreadPoolExecutor@279f2327[Running, pool size = 17, active threads = 17, queued tasks = 128, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at kim.hsl.threadpool.ThreadPool.main(ThreadPool.java:90)



解决方案 : 为线程池设置 RejectedExecutionHandler , 该处理器需要开发者自定义 , 实现 RejectedExecutionHandler 接口 , 并实现其 rejectedExecution 方法 ;


   

THREAD_POOL_EXECUTOR.setRejectedExecutionHandler(new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
                // 自定义任务被拒绝后的处理策略
                System.out.println("任务被拒绝");
            }
        });






三、完整代码示例


package kim.hsl.threadpool;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPool {
    /*
        自定义线程池使用示例
        自己配置线程池的各种参数
        模仿 AsyncTask 使用线程池
        部分代码从 AsyncTask 类中拷贝过来
     */
    /**
     * 获取当前的 CPU 核数
     */
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    /**
     * 线程池核心线程数
     * 线程池中最少 2 个线程 , 最多 4 个线程 ,
     * 最好是选择 CPU 核数 - 1 个 , 避免后台任务使 CPU 性能饱和
     */
    private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
    /**
     * 最大线程数
     */
    private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
    /**
     * 非核心线程最大闲置时间
     */
    private static final int KEEP_ALIVE_SECONDS = 30;
    /**
     * 线程工厂
     * 用于创建线程
     */
    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());
        }
    };
    /**
     * 线程池任务队列
     * 最多可以容纳 128 个可执行的任务
     */
    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(128);
    /**
     * 并行执行任务的线程池执行者
     */
    public static final ThreadPoolExecutor THREAD_POOL_EXECUTOR;
    static {
        /*
            在静态代码块中初始化线程池
            在构造函数中对线程池进行配置 , 配置内容包括 :
            核心线程数
            最大线程数
            非核心线程最大限制时间
            闲置时间的时间单位
            线程池任务队列
            线程创建工厂
         */
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
                sPoolWorkQueue, sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        THREAD_POOL_EXECUTOR = threadPoolExecutor;
    }
    public static void main(String[] args) {
        THREAD_POOL_EXECUTOR.setRejectedExecutionHandler(new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
                // 自定义任务被拒绝后的处理策略
                System.out.println("任务被拒绝");
            }
        });
        /*
            线程池中只有 128 个任务队列 , 一次性写入 150 个
            任务队列满了以后, 会拒绝任务
            报错信息如下 :
            Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task kim.hsl.threadpool.ThreadPool$2@1f32e575 rejected from java.util.concurrent.ThreadPoolExecutor@279f2327[Running, pool size = 17, active threads = 17, queued tasks = 128, completed tasks = 0]
            at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
            at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
            at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
            at kim.hsl.threadpool.ThreadPool.main(ThreadPool.java:90)
         */
        for(int i = 0; i < 150; i ++ ){
            THREAD_POOL_EXECUTOR.execute(
                    new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Thread.sleep(1_000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
            );
        }
    }
}




运行结果 :


---- IntelliJ IDEA coverage runner ---- 
sampling ...
include patterns:
kim\.hsl\.threadpool\..*
exclude patterns:
任务被拒绝
任务被拒绝
任务被拒绝
任务被拒绝
任务被拒绝
Class transformation time: 0.018846207s for 141 classes or 1.336610425531915E-4s per class



目录
相关文章
|
22天前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
46 1
|
26天前
|
数据采集 XML JavaScript
C# 中 ScrapySharp 的多线程下载策略
C# 中 ScrapySharp 的多线程下载策略
|
4天前
|
存储 缓存 Java
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
什么是线程池?从底层源码入手,深度解析线程池的工作原理
|
30天前
|
缓存 Java
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
这篇文章详细介绍了Java中线程的四种初始化方式,包括继承Thread类、实现Runnable接口、实现Callable接口与FutureTask结合使用,以及使用线程池。同时,还深入探讨了线程池的七大参数及其作用,解释了线程池的运行流程,并列举了四种常见的线程池类型。最后,阐述了在开发中使用线程池的原因,如降低资源消耗、提高响应速度和增强线程的可管理性。
异步&线程池 线程池的七大参数 初始化线程的4种方式 【上篇】
|
15天前
|
监控 Java
线程池中线程异常后:销毁还是复用?技术深度剖析
在并发编程中,线程池作为一种高效利用系统资源的工具,被广泛用于处理大量并发任务。然而,当线程池中的线程在执行任务时遇到异常,如何妥善处理这些异常线程成为了一个值得深入探讨的话题。本文将围绕“线程池中线程异常后:销毁还是复用?”这一主题,分享一些实践经验和理论思考。
29 3
|
20天前
|
监控 负载均衡 算法
线程数突增!领导说再这么写就GC掉我:深入理解与优化策略
【8月更文挑战第29天】在软件开发的世界里,性能优化总是开发者们绕不开的话题。特别是当面对“线程数突增”这样的紧急情况时,更是考验着我们的技术功底和问题解决能力。今天,我们就来深入探讨这一话题,分享一些工作学习中积累的技术干货,帮助大家避免被“GC”(垃圾回收,也常用来幽默地表示“被炒鱿鱼”)的尴尬。
34 2
|
27天前
|
存储 监控 Java
|
25天前
|
缓存 Java 调度
【Java 并发秘籍】线程池大作战:揭秘 JDK 中的线程池家族!
【8月更文挑战第24天】Java的并发库提供多种线程池以应对不同的多线程编程需求。本文通过实例介绍了四种主要线程池:固定大小线程池、可缓存线程池、单一线程线程池及定时任务线程池。固定大小线程池通过预设线程数管理任务队列;可缓存线程池能根据需要动态调整线程数量;单一线程线程池确保任务顺序执行;定时任务线程池支持周期性或延时任务调度。了解并正确选用这些线程池有助于提高程序效率和资源利用率。
33 2
|
25天前
|
存储 Java 开发者
HashMap线程安全问题大揭秘:ConcurrentHashMap、自定义同步,一文让你彻底解锁!
【8月更文挑战第24天】HashMap是Java集合框架中不可或缺的一部分,以其高效的键值对存储和快速访问能力广受开发者欢迎。本文深入探讨了HashMap在JDK 1.8后的底层结构——数组+链表+红黑树混合模式,这种设计既利用了数组的快速定位优势,又通过链表和红黑树有效解决了哈希冲突问题。数组作为基石,每个元素包含一个Node节点,通过next指针形成链表;当链表长度过长时,采用红黑树进行优化,显著提升性能。此外,还介绍了HashMap的扩容机制,确保即使在数据量增大时也能保持高效运作。通过示例代码展示如何使用HashMap进行基本操作,帮助理解其实现原理及应用场景。
26 1
|
18天前
|
前端开发 JavaScript 大数据
React与Web Workers:开启前端多线程时代的钥匙——深入探索计算密集型任务的优化策略与最佳实践
【8月更文挑战第31天】随着Web应用复杂性的提升,单线程JavaScript已难以胜任高计算量任务。Web Workers通过多线程编程解决了这一问题,使耗时任务独立运行而不阻塞主线程。结合React的组件化与虚拟DOM优势,可将大数据处理等任务交由Web Workers完成,确保UI流畅。最佳实践包括定义清晰接口、加强错误处理及合理评估任务特性。这一结合不仅提升了用户体验,更为前端开发带来多线程时代的全新可能。
22 0