Android线程池封装库

目录介绍

  • 1.遇到的问题和需求
  • 1.1 遇到的问题有哪些
  • 1.2 遇到的需求
  • 1.3 多线程经过实现Runnable弊端
  • 1.4 为何要用线程池
  • 2.封装库具备的功能
  • 2.1 经常使用的功能
  • 3.封装库的具体使用
  • 3.1 一键集成
  • 3.2 在application中初始化库
  • 3.3 最简单的runnable线程调用方式
  • 3.4 最简单的异步回调
  • 4.线程池封装思路介绍
  • 4.1 自定义Runnable和Callable类
  • 4.2 添加回调接口Callback
  • 4.3 建立线程池配置文件
  • 4.4 建立java和android平台消息器
  • 4.5 建立PoolThread继承Executor
  • 4.6 使用builder模式获取线程池对象
  • 4.7 灵活建立线程池[重点]
  • 4.8 启动线程池中的任务
  • 4.9 如何关闭线程池操做
  • 5.其余介绍
  • 5.1 参考的开源案例
  • 5.2 参考的博客

好消息

  • 博客笔记大汇总【16年3月到至今】,包括Java基础及深刻知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,固然也在工做之余收集了大量的面试题,长期更新维护而且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!
  • 连接地址:https://github.com/yangchong211/YCBlogs
  • 若是以为好,能够star一下,谢谢!固然也欢迎提出建议,万事起于忽微,量变引发质变!

0.前言介绍

  • 轻量级线程池封装库,支持线程执行过程当中状态回调监测(包含成功,失败,异常等多种状态);支持建立异步任务,而且能够设置线程的名称,延迟执行时间,线程优先级,回调callback等;能够根据本身须要建立本身须要的线程池,一共有四种;线程异常时,能够打印异常日志,避免崩溃。
  • 关于线程池,对于开发来讲是十分重要,可是又有点难以理解或者运用。关于写线程池的博客网上已经有不少了,可是通常不多有看到的实际案例或者封装的库,许多博客也仅仅是介绍了线程池的概念,方法,或者部分源码分析,那么为了方便管理线程任务操做,因此才想结合实际案例是否是更容易理解线程池,更多能够参考代码。

线程池封装库GitHub连接:https://github.com/yangchong211/YCThreadPool

1.遇到的问题和需求

1.1 遇到的问题有哪些?

  • 继承Thread,或者实现接口Runnable来开启一个子线程,没法准确地知道线程何时执行完成并得到到线程执行完成后返回的结果
  • 当线程出现异常的时候,如何避免致使崩溃问题?博客

1.2 遇到的需求

  • 如何在实际开发中配置线程的优先级
  • 开启一个线程,是否能够监听Runnable接口中run方法操做的过程,好比监听线程的状态开始,成功,异常,完成等多种状态。
  • 开启一个线程,是否能够监听Callable<T>接口中call()方法操做的过程,好比监听线程的状态开始,错误异常,完成等多种状态。

1.3 多线程经过实现Runnable弊端

  • 1.3.1 通常开启线程的操做以下所示
    new Thread(new Runnable() {
        @Override
        public void run() {
            //作一些任务 } }).start(); 
  • 建立了一个线程并执行,它在任务结束后GC会自动回收该线程。
  • 在线程并发很少的程序中确实不错,而假如这个程序有不少地方须要开启大量线程来处理任务,那么若是仍是用上述的方式去建立线程处理的话,那么将致使系统的性能表现的很是糟糕。博客
  • 1.3.2 主要的弊端有这些,可能总结并不全面
  • 大量的线程建立、执行和销毁是很是耗cpu和内存的,这样将直接影响系统的吞吐量,致使性能急剧降低,若是内存资源占用的比较多,还极可能形成OOM
  • 大量的线程的建立和销毁很容易致使GC频繁的执行,从而发生内存抖动现象,而发生了内存抖动,对于移动端来讲,最大的影响就是形成界面卡顿
  • 线程的建立和销毁都须要时间,当有大量的线程建立和销毁时,那么这些时间的消耗则比较明显,将致使性能上的缺失

1.4 为何要用线程池

  • 使用线程池管理线程优势
    • ①下降系统资源消耗,经过重用已存在的线程,下降线程建立和销毁形成的消耗;
    • ②提升系统响应速度,当有任务到达时,无需等待新线程的建立便能当即执行;
    • ③方便线程并发数的管控,线程如果无限制的建立,不只会额外消耗大量系统资源,更是占用过多资源而阻塞系统或oom等情况,从而下降系统的稳定性。线程池能有效管控线程,统一分配、调优,提供资源使用率;
    • ④更强大的功能,线程池提供了定时、按期以及可控线程数等功能的线程池,使用方便简单。

1.5 线程池执行流程

  • 大概的流程图以下
    • image
  • 文字描述以下
    • ①若是在线程池中的线程数量没有达到核心的线程数量,这时候就回启动一个核心线程来执行任务。
    • ②若是线程池中的线程数量已经超过核心线程数,这时候任务就会被插入到任务队列中排队等待执行。
    • ③因为任务队列已满,没法将任务插入到任务队列中。这个时候若是线程池中的线程数量没有达到线程池所设定的最大值,那么这时候就会当即启动一个非核心线程来执行任务。
    • ④若是线程池中的数量达到了所规定的最大值,那么就会拒绝执行此任务,这时候就会调用RejectedExecutionHandler中的rejectedExecution方法来通知调用者。博客

2.封装库具备的功能

2.1 经常使用的功能

  • 支持线程执行过程当中状态回调监测(包含成功,失败,异常等多种状态)
  • 支持线程异常检测,而且能够打印异常日志
  • 支持设置线程属性,好比名称,延时时长,优先级,callback
  • 支持异步开启线程任务,支持监听异步回调监听
  • 方便集成,方便使用,能够灵活选择建立不一样的线程池

3.封装库的具体使用

3.1 一键集成

  • compile 'cn.yc:YCThreadPoolLib:1.3.0'

3.2 在application中初始化库

  • 代码以下所示
    public class App extends Application{
    
        private static App instance;
        private PoolThread executor;
    
        public static synchronized App getInstance() {
            if (null == instance) {
                instance = new App();
            }
            return instance;
        }
    
        public App(){}
    
        @Override
        public void onCreate() {
            super.onCreate();
            instance = this;
            //初始化线程池管理器 initThreadPool(); } /** * 初始化线程池管理器 */ private void initThreadPool() { // 建立一个独立的实例进行使用 executor = PoolThread.ThreadBuilder .createFixed(5) .setPriority(Thread.MAX_PRIORITY) .setCallback(new LogCallback()) .build(); } /** * 获取线程池管理器对象,统一的管理器维护全部的线程池 * @return executor对象 */ public PoolThread getExecutor(){ return executor; } } //自定义回调监听callback,能够全局设置,也能够单独设置。都行 public class LogCallback implements ThreadCallback { private final String TAG = "LogCallback"; @Override public void onError(String name, Throwable t) { Log.e(TAG, "LogCallback"+"------onError"+"-----"+name+"----"+Thread.currentThread()+"----"+t.getMessage()); } @Override public void onCompleted(String name) { Log.e(TAG, "LogCallback"+"------onCompleted"+"-----"+name+"----"+Thread.currentThread()); } @Override public void onStart(String name) { Log.e(TAG, "LogCallback"+"------onStart"+"-----"+name+"----"+Thread.currentThread()); } } 

3.3 最简单的runnable线程调用方式

  • 关于设置callback回调监听,我这里在app初始化的时候设置了全局的logCallBack,因此这里没有添加,对于每一个单独的执行任务,能够添加独立callback。
    PoolThread executor = App.getInstance().getExecutor();
            executor.setName("最简单的线程调用方式"); executor.setDeliver(new AndroidDeliver()); executor.execute(new Runnable() { @Override public void run() { Log.e("MainActivity","最简单的线程调用方式"); } }); 

3.4 最简单的异步回调

  • 以下所示
    PoolThread executor = App.getInstance().getExecutor();
            executor.setName("异步回调"); executor.setDelay(2,TimeUnit.MILLISECONDS); // 启动异步任务 executor.async(new Callable<Login>(){ @Override public Login call() throws Exception { // 作一些操做 return null; } }, new AsyncCallback<Login>() { @Override public void onSuccess(Login user) { Log.e("AsyncCallback","成功"); } @Override public void onFailed(Throwable t) { Log.e("AsyncCallback","失败"); } @Override public void onStart(String threadName) { Log.e("AsyncCallback","开始"); } }); 

4.线程池封装思路介绍

4.1 自定义Runnable和自定义Callable类

  • 4.1.1 首先看看Runnable和Callable接口代码php

    public interface Runnable {
        public void run();
    }
    
    public interface Callable<V> {
        V call() throws Exception;
    }
  • 4.1.2 Runnable和Callable接口是干什么的html

  • Runnable 从 JDK1.0 开始就有了,Callable 是在 JDK1.5 增长的。java

  • Thread调用了Runnable接口中的方法用来在线程中执行任务。Runnable 和 Callable 都表明那些要在不一样的线程中执行的任务。android

  • Thread调用了Runnable接口中的方法用来在线程中执行任务。博客git

  • 4.1.3 Runnable和Callable接口有何区别
  • 它们的主要区别是 Callable 的 call() 方法能够返回值和抛出异常,而 Runnable 的 run() 方法没有这些功能。Callable 能够返回装载有计算结果的 Future 对象。博客
  • 比较两个接口,能够得出这样结论:
  • Callable 的任务执行后可返回值,而 Runnable 的任务是不能返回值的
  • call() 方法能够抛出异常,run()方法不能够的
  • 运行 Callable 任务能够拿到一个 Future 对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。经过 Future 对象能够了解任务执行状况,可取消任务的执行,还可获取执行结果;
  • 4.1.4 自定义Runnable包装类,重点看run方法代码逻辑
    public final class RunnableWrapper implements Runnable {
    
        private String name;
        private CallbackDelegate delegate;
        private Runnable runnable;
        private Callable callable;
    
        public RunnableWrapper(ThreadConfigs configs) {
            this.name = configs.name;
            this.delegate = new CallbackDelegate(configs.callback, configs.deliver, configs.asyncCallback);
        }
    
        /**
         * 启动异步任务,普通的 * @param runnable runnable * @return 对象 */ public RunnableWrapper setRunnable(Runnable runnable) { this.runnable = runnable; return this; } /** * 异步任务,回调用于接收可调用任务的结果 * @param callable callable * @return 对象 */ public RunnableWrapper setCallable(Callable callable) { this.callable = callable; return this; } /** * 自定义xxRunnable继承Runnable,实现run方法 * 详细能够看个人GitHub:https://github.com/yangchong211 */ @Override public void run() { Thread current = Thread.currentThread(); ThreadToolUtils.resetThread(current, name, delegate); //开始 delegate.onStart(name); //注意须要判断runnable,callable非空 // avoid NullPointException if (runnable != null) { runnable.run(); } else if (callable != null) { try { Object result = callable.call(); //监听成功 delegate.onSuccess(result); } catch (Exception e) { //监听异常 delegate.onError(name, e); } } //监听完成 delegate.onCompleted(name); } } 
  • 4.1.5 自定义Callable<T>包装类,重点看call方法代码逻辑
    public final class CallableWrapper<T> implements Callable<T> {
    
        private String name;
        private ThreadCallback callback;
        private Callable<T> proxy;
    
        /**
         * 构造方法 * @param configs thread配置,主要参数有:线程name,延迟time,回调callback,异步callback * @param proxy 线程优先级 */ public CallableWrapper(ThreadConfigs configs, Callable<T> proxy) { this.name = configs.name; this.proxy = proxy; this.callback = new CallbackDelegate(configs.callback, configs.deliver, configs.asyncCallback); } /** * 详细能够看个人GitHub:https://github.com/yangchong211 * 自定义Callable继承Callable<T>类,Callable 是在 JDK1.5 增长的。 * Callable 的 call() 方法能够返回值和抛出异常 * @return 泛型 * @throws Exception 异常 */ @Override public T call() { ThreadToolUtils.resetThread(Thread.currentThread(),name,callback); if (callback != null) { //开始 callback.onStart(name); } T t = null; try { t = proxy == null ? null : proxy.call(); } catch (Exception e) { e.printStackTrace(); //异常错误 if(callback!=null){ callback.onError(name,e); } }finally { //完成 if (callback != null) { callback.onCompleted(name); } } return t; } } 

4. 添加回调接口AsyncCallback和ThreadCallback

  • 注意,这个写的自定义callback,须要添加多种状态,你能够自定义其余状态。看完了这里再回过头看看RunnableWrapper中run方法和CallableWrapper中call方法的逻辑。博客
  • 4.0 为何要这样设计
  • 它可让程序员准确地知道线程何时执行完成并得到到线程执行完成后返回的结果。
  • AsyncCallback,在这个类中,能够看到三种状态[这个是在自定义Runnable中的run方法中实现],而且成功时能够携带结果,在异常时还能够打印异常日志。
  • ThreadCallback,在这个类中,能够看到三种状态[这个是在自定义Callable<T>中的call方法中实现],而且在异常时能够打印异常日志,在开始和完成时能够打印线程名称
  • 4.1 AsyncCallback类代码以下所示程序员

    /**
     * <pre>
     *     @author      杨充 * blog https://www.jianshu.com/p/53017c3fc75d * time * desc 异步callback回调接口 * revise * GitHub https://github.com/yangchong211 * </pre> */ public interface AsyncCallback<T> { /** * 成功时调用 * @param t 泛型 */ void onSuccess(T t); /** * 异常时调用 * @param t 异常 */ void onFailed(Throwable t); /** * 通知用户任务开始运行 * @param threadName 正在运行线程的名字 */ void onStart(String threadName); } 
  • 4.2 ThreadCallback类代码以下所示github

    /**
     * <pre>
     *     @author: yangchong
     *     blog  : https://github.com/yangchong211
     *     time  :
     *     desc  : 一个回调接口,用于通知用户任务的状态回调委托类 * 线程的名字能够自定义 * revise: * </pre> */ public interface ThreadCallback { /** * 当线程发生错误时,将调用此方法。 * @param threadName 正在运行线程的名字 * @param t 异常 */ void onError(String threadName, Throwable t); /** * 通知用户知道它已经完成 * @param threadName 正在运行线程的名字 */ void onCompleted(String threadName); /** * 通知用户任务开始运行 * @param threadName 正在运行线程的名字 */ void onStart(String threadName); } 

4.3 建立线程池配置文件

  • 为何要添加配置文件,配置文件的做用主要是存储当前任务的某些配置,好比线程的名称,回调callback等等这些参数。还能够用于参数的传递!
    public final class ThreadConfigs {
        /**
         * 线程的名称 * 经过setName方法设置 */ public String name; /** * 线程执行延迟的时间 * 经过setDelay方法设置 */ public long delay; /** * 线程执行者 * JAVA或者ANDROID */ public Executor deliver; /** * 用户任务的状态回调callback */ public ThreadCallback callback; /** * 异步callback回调callback */ public AsyncCallback asyncCallback; } 

4.4 建立java平台和android平台消息器Executor

  • 在android环境下,想想callback回调类中的几个方法,好比回调失败,回调成功,或者回调完成,可能会作一些操做UI界面的操做逻辑,那么都知道子线程是不能更新UI的,因此必须放到主线程中操做。
  • 可是在Java环境下,回调方法所运行的线程与任务执行线程其实能够保持一致。
  • 所以,这里须要设置该消息器用来区别回调的逻辑。主要做用是指定回调任务须要运行在什么线程之上。
  • 4.4.1 android环境下 image
  • 4.4.2 java环境下 image
  • 4.4.3 如何判断环境是java环境仍是Android环境呢
    public final class ThreadToolUtils {
    
        /**
         * 标志:是否在android平台上 */ public static boolean isAndroid; /* * 静态代码块 * 判断是不是android环境 * Class.forName(xxx.xx.xx) 返回的是一个类对象 * 首先要明白在java里面任何class都要装载在虚拟机上才能运行。 */ static { try { Class.forName("android.os.Build"); isAndroid = true; } catch (Exception e) { isAndroid = false; } } } 

4.5 建立PoolThread继承Executor

  • 这里只是展现部分代码,若是想看完整的代码,能够直接看案例。博客
  • 4.5.1 继承Executor接口,而且实现execute方法
    public final class PoolThread implements Executor{
    
       
        /**
         * 启动任务 * 这个是实现接口Executor中的execute方法 * 提交任务无返回值 * @param runnable task,注意添加非空注解 */ @Override public void execute (@NonNull Runnable runnable) { //获取线程thread配置信息 ThreadConfigs configs = getLocalConfigs(); //设置runnable任务 runnable = new RunnableWrapper(configs).setRunnable(runnable); //启动任务 DelayTaskDispatcher.get().postDelay(configs.delay, pool, runnable); //重置线程Thread配置 resetLocalConfigs(); } /** * 当启动任务或者发射任务以后须要调用该方法 * 重置本地配置,置null */ private synchronized void resetLocalConfigs() { local.set(null); } /** * 注意须要用synchronized修饰,解决了多线程的安全问题 * 获取本地配置参数 * @return */ private synchronized ThreadConfigs getLocalConfigs() { ThreadConfigs configs = local.get(); if (configs == null) { configs = new ThreadConfigs(); configs.name = defName; configs.callback = defCallback; configs.deliver = defDeliver; local.set(configs); } return configs; } } 

4.6 使用builder模式获取线程池对象

  • 4.6.1 看下builder模式下代码
  • 若是还不是很熟悉builder模式,欢迎阅读个人另一篇文章之——设计模式之二:Builder模式:https://www.jianshu.com/p/246b01ca84c2
  • 也能够看Android源码设计模式这本书,很不错
  • 直接列出代码,以下所示:
    public final class PoolThread implements Executor{
    
        //省略部分代码…… public static class ThreadBuilder { final static int TYPE_CACHE = 0; final static int TYPE_FIXED = 1; final static int TYPE_SINGLE = 2; final static int TYPE_SCHEDULED = 3; int type; int size; int priority = Thread.NORM_PRIORITY; String name; ThreadCallback callback; Executor deliver; ExecutorService pool; private ThreadBuilder(int size, int type, ExecutorService pool) { this.size = Math.max(1, size); this.type = type; this.pool = pool; } /** * 经过Executors.newSingleThreadExecutor()建立线程池 * 内部只有一个核心线程,全部任务进来都要排队按顺序执行 */ public static ThreadBuilder create(ExecutorService pool) { return new ThreadBuilder(1, TYPE_SINGLE, pool); } /** * 经过Executors.newCachedThreadPool()建立线程池 * 它是一个数量无限多的线程池,都是非核心线程,适合执行大量耗时小的任务 */ public static ThreadBuilder createCacheable() { return new ThreadBuilder(0, TYPE_CACHE, null); } /** * 经过Executors.newFixedThreadPool()建立线程池 * 线程数量固定的线程池,所有为核心线程,响应较快,不用担忧线程会被回收。 */ public static ThreadBuilder createFixed(int size) { return new ThreadBuilder(size, TYPE_FIXED, null); } /** * 经过Executors.newScheduledThreadPool()建立线程池 * 有数量固定的核心线程,且有数量无限多的非核心线程,适合用于执行定时任务和固定周期的重复任务 */ public static ThreadBuilder createScheduled(int size) { return new ThreadBuilder(size, TYPE_SCHEDULED, null); } /** * 经过Executors.newSingleThreadPool()建立线程池 * 内部只有一个核心线程,全部任务进来都要排队按顺序执行 * 和create区别是size数量 */ public static ThreadBuilder createSingle() { return new ThreadBuilder(0, TYPE_SINGLE, null); } /** * 将默认线程名设置为“已使用”。 */ public ThreadBuilder setName (@NonNull String name) { if (name.length()>0) { this.name = name; } return this; } /** * 将默认线程优先级设置为“已使用”。 */ public ThreadBuilder setPriority (int priority) { this.priority = priority; return this; } /** * 将默认线程回调设置为“已使用”。 */ public ThreadBuilder setCallback (ThreadCallback callback) { this.callback = callback; return this; } /** * 设置默认线程交付使用 */ public ThreadBuilder setDeliver(Executor deliver) { this.deliver = deliver; return this; } /** * 建立用于某些配置的线程管理器。 * @return 对象 */ public PoolThread build () { //最大值 priority = Math.max(Thread.MIN_PRIORITY, priority); //最小值 priority = Math.min(Thread.MAX_PRIORITY, priority); size = Math.max(1, size); if (name==null || name.length()==0) { // 若是没有设置名字,那么就使用下面默认的线程名称 switch (type) { case TYPE_CACHE: name = "CACHE"; break; case TYPE_FIXED: name = "FIXED"; break; case TYPE_SINGLE: name = "SINGLE"; break; default: name = "POOL_THREAD"; break; } } if (deliver == null) { if (ThreadToolUtils.isAndroid) { deliver = AndroidDeliver.getInstance(); } else { deliver = JavaDeliver.getInstance(); } } return new PoolThread(type, size, priority, name, callback, deliver, pool); } } } 
  • 4.6.2 添加设置thread配置信息的方法
    /**
     * 为当前的任务设置线程名。 * @param name 线程名字 * @return PoolThread */ public PoolThread setName(String name) { getLocalConfigs().name = name; return this; } /** * 设置当前任务的线程回调,若是未设置,则应使用默认回调。 * @param callback 线程回调 * @return PoolThread */ public PoolThread setCallback (ThreadCallback callback) { getLocalConfigs().callback = callback; return this; } /** * 设置当前任务的延迟时间. * 只有当您的线程池建立时,它才会产生效果。 * @param time 时长 * @param unit time unit * @return PoolThread */ public PoolThread setDelay (long time, TimeUnit unit) { long delay = unit.toMillis(time); getLocalConfigs().delay = Math.max(0, delay); return this; } /** * 设置当前任务的线程传递。若是未设置,则应使用默认传递。 * @param deliver thread deliver * @return PoolThread */ public PoolThread setDeliver(Executor deliver){ getLocalConfigs().deliver = deliver; return this; } 
  • 4.6.3 看下builder模式下建立对象的代码
  • 经过调用ThreadBuilder类中的build()方法建立属于本身的线程池。
  • 最后经过new PoolThread(type, size, priority, name, callback, deliver, pool)建立对象,而且做为返回值返回。
  • 而后再来看看PoolThread方法,这部分看目录4.7部分介绍。博客

4.7 灵活建立线程池[重点]

  • 4.7.1 建立线程池的五种方法
  • 经过Executors的工厂方法获取这五种线程池
  • 经过Executors的工厂方法来建立线程池极其简便,其实它的内部仍是经过new ThreadPoolExecutor(…)的方式建立线程池的,具体能够看看源码,这里省略呢……
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
    ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    ScheduledExecutorService singleThreadScheduledPool = Executors.newSingleThreadScheduledExecutor();
  • 4.7.2 灵活建立不一样类型线程池
  • 设计的时候,但愿可以选择性地建立本身想要的线程池,而且动态设置线程的数量,还能够设置线程优先级。
  • 4.7.2.1 建立不一样类型线程池代码以下所示:
    /**
     * 建立线程池,目前支持如下四种 * @param type 类型 * @param size 数量size * @param priority 优先级 * @return */ private ExecutorService createPool(int type, int size, int priority) { switch (type) { case Builder.TYPE_CACHE: //它是一个数量无限多的线程池,都是非核心线程,适合执行大量耗时小的任务 return Executors.newCachedThreadPool(new DefaultFactory(priority)); case Builder.TYPE_FIXED: //线程数量固定的线程池,所有为核心线程,响应较快,不用担忧线程会被回收。 return Executors.newFixedThreadPool(size, new DefaultFactory(priority)); case Builder.TYPE_SCHEDULED: //有数量固定的核心线程,且有数量无限多的非核心线程,适合用于执行定时任务和固定周期的重复任务 return Executors.newScheduledThreadPool(size, new DefaultFactory(priority)); case Builder.TYPE_SINGLE: default: //内部只有一个核心线程,全部任务进来都要排队按顺序执行 return Executors.newSingleThreadExecutor(new DefaultFactory(priority)); } } 
  • 4.7.2.1 了解一下ThreadFactory接口做用
  • 关于ThreadFactory接口的源代码以下所示:
  • 以看到ThreadFactory中,只有一个newThread方法,它负责接收一个Runnable对象,并将其封装到Thread对象中,进行执行。
  • 经过有道词典对这个类的说明进行翻译是:根据须要建立新线程的对象。使用线程工厂能够消除对{@link Thread#Thread(Runnable)新线程}的硬链接,从而使应用程序可以使用特殊的线程子类、优先级等。
    public interface ThreadFactory {
    
        /**
         * Constructs a new {@code Thread}.  Implementations may also initialize
         * priority, name, daemon status, {@code ThreadGroup}, etc.
         *
         * @param r a runnable to be executed by new thread instance
         * @return constructed thread, or {@code null} if the request to
         *         create a thread is rejected
         */
        Thread newThread(Runnable r);
    }
  • 4.7.2.3 建立默认MyThreadFactory继承ThreadFactory
  • 建立一个默认的MyThreadFactory,而且这个类继承ThreadFactory,实现接口中的newThread方法。而后在newThread方法中建立线程,而且设置线程优先级。
  • 建立一个优先级线程池很是有用,它能够在线程池中线程数量不足或系统资源紧张时,优先处理咱们想要先处理的任务,而优先级低的则放到后面再处理,这极大改善了系统默认线程池以FIFO方式处理任务的不灵活。
  • 代码以下所示
    public class MyThreadFactory implements ThreadFactory {
    
        private int priority;
        public MyThreadFactory(int priority) {
            this.priority = priority;
        }
    
        @Override
        public Thread newThread(@NonNull Runnable runnable) {
            Thread thread = new Thread(runnable);
            thread.setPriority(priority);
            return thread;
        }
    
    }

4.8 启动线程池中的任务

  • 具体逻辑看DelayTaskExecutor中的postDelay方法
    /**
     * 启动 * @param delay 延迟执行的时间,注意默认单位是TimeUnit.MILLISECONDS * @param pool pool线程池 * @param task runnable */ void postDelay(long delay, final ExecutorService pool, final Runnable task) { if (delay == 0) { //若是时间是0,那么普通开启 pool.execute(task); return; } //延时操做 dispatcher.schedule(new Runnable() { @Override public void run() { //在未来的某个时间执行给定的命令。该命令能够在新线程、池线程或调用线程中执行 pool.execute(task); } }, delay, TimeUnit.MILLISECONDS); } 

4.9 如何关闭线程池操做

  • 代码以下所示
    /** * 关闭线程池操做 */ public void stop(){ try { // shutdown只是起到通知的做用 // 只调用shutdown方法结束线程池是不够的 pool.shutdown(); // (全部的任务都结束的时候,返回TRUE) if(!pool.awaitTermination(0, TimeUnit.MILLISECONDS)){ // 超时的时候向线程池中全部的线程发出中断(interrupted)。 pool.shutdownNow(); } } catch (InterruptedException e) { // awaitTermination方法被中断的时候也停止线程池中所有的线程的执行。 e.printStackTrace(); } finally { pool.shutdownNow(); } } 

5.其余介绍

5.1 参考的开源案例

5.2 参考的博客

其余介绍

01.关于博客汇总连接

02.关于个人博客

线程池封装库GitHub连接:https://github.com/yangchong211/YCThreadPool

相关文章
相关标签/搜索