参考链接
https://blog.csdn.net/u012702547/article/details/52259529
https://blog.csdn.net/wolf909867753/article/details/77500625

普通线程的劣势

通常,在Android中使用线程的话,基本使用new Thread来创建线程
例如

new Thread(new Runnable() {              @Override              public void run() {                  //耗时操作             }          }).start();  

但是在Java中,创建线程是消耗资源的,频繁的创建和销毁线程是相当消耗资源的,为此,引入了线程池的概念。

线程池的优势

使用线程池可以指定并发线程数,可以控制线程延时启动,可以设定线程阻塞超时(超时后从等待队列移除)等等,可以更好的控制线程,而不像new Thread一样,无法管控
一般情况下,任务的执行,主要时间消耗在如下几个部分
1.线程创建时间T1 2.任务等待线程执行时间T2 3.线程执行任务时间T3 4.线程销毁时间T4
通常,任务执行的时间取决于CPU的性能,所以T3相对可优化性不高,那么就智能优化T1 T2 T4了
我们可以通过合理创建线程数,减少不必要线程的创建销毁以减少T1 T4,合理维持线程空转(时刻等待任务,减少任务等待时间),以便有任务立刻执行,减小T2。后面我们会在实例中看到各种运用。

线程池的主要组成

线程池主要有以下四个部分,以下摘自本文

1.线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2.工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3.任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4.任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。

Android中常见的线程池

  • ThreadPoolExecutor
    构造方法
    ThreadPoolExecutor构造方法有多个,只介绍参数较多的这个构造方法:
    public ThreadPoolExecutor(int corePoolSize,                              int maximumPoolSize,                              long keepAliveTime,                              TimeUnit unit,                              BlockingQueue workQueue,                              ThreadFactory threadFactory,                              RejectedExecutionHandler handler) {        ...    }

int corePoolSize:核心线程数,始终运行在线程池中的线程数,及时这些线程是空闲状态也不会销毁,除非指定了allowCoreThreadTimeOut参数

corePoolSize the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set

int maximumPoolSize:

maximumPoolSize the maximum number of threads to allow in the pool

线程池最大线程数
long keepAliveTime:

keepAliveTime when the number of threads is greater than the core, this is the maximum time that excess idle threads

非核心线程空闲的超时时间,如果非核心线程任务执行完毕,空闲状态超过keepAliveTime,则会被GC。如果allowCoreThreadTimeOut被指定,该参数也指核心线程超时时间
TimeUnit unit:

unit the time unit for the {@code keepAliveTime} argument

keepAliveTime的单位,指以下几种
NANOSECONDS
MICROSECONDS
MILLISECONDS
SECONDS
MINUTES
HOURS
DAYS

BlockingQueue workQueue:

workQueue the queue to use for holding tasks before they are executed.
This queue will hold only the {@code Runnable} tasks submitted by the
{@code execute} method.

工作队列,当线程数达到maximumPoolSize时,新创建的线程会被放到workQueue中等待其他线程执行完毕
corePoolSize maximumPoolSize workQueue三者数量关系:
corePoolSize为核心线程数
maximumPoolSize为核心线程+非核心线程数
workQueue为线程等待数
任务执行的优先级是这样的:如果有空闲的核心线程,交给核心线程,否则放到workQueue中,如果workQueue已满,则看看非核心线程是否满了,未满,放入非核心线程,否则抛出异常。
也就是:当创建的线程数>(maximumPoolSize+workQueue),则线程数量超出上限,抛出异常

ThreadFactory threadFactory:

threadFactory the factory to use when the executor creates a new
thread

用来创建线程的ThreadFactory类型。ThreadFactory是一个接口,通常需要指定实现类。常见实现类有以下两个
Executors.DefaultThreadFactory
Executors.PrivilegedThreadFactory
通常只要使用默认的ThreadFactory即可,除非自定义线程池才会使用到自定义ThreadFactory。自定义ThreadFactory需要指定线程优先级,name,守护状态,ThreadGroup等参数。

RejectedExecutionHandler handler:

handler the handler to use when execution is blocked because the
thread bounds and queue capacities are reached

当线程池中的线程数量已经达到最大数,会拒绝接受task,抛出异常。

特性
参数较多,基本可以定义自己想要的线程池,下面介绍的几种线程池大多数都可以通过指定ThreadPoolExecutor的参数来实现相同的效果
例子

    public static void main(String [] args){        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(3, 5,                  1, TimeUnit.SECONDS, new LinkedBlockingDeque(10));        for (int i = 0; i < 15; i++) {              final int INDEX = i;              Runnable runnable = new Runnable() {                public void run() {                      try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("CHJ"+"run: " + INDEX);                }              };              poolExecutor.execute(runnable);          }      }

创建线程池,核心线程3 非核心线程2(5-3),线程队列10(最大任务数15)

大家可能对LinkedBlockingDeque比较陌生,这其实是BlockingQueue的具体实现类。
BlockingQueue常见实现类:

ArrayBlockingQueue 实现基于数组,需指定大小,线程遵循FIFO(先入先出)
LinkedBlockingQueue 实现基于链表,可以不指定大小,此时队列大小为Integer.MAX_VALUE(也可指定大小),线程遵循FIFO(先入先出)
PriorityBlockingQueue 实现基于priority heap,无大小限制(逻辑上),添加线程操作可能由于OutOfMemoryError而失败,排序方式依赖Comparable(意味着队列中的任务是实现了Comparable的)
SynchronousQueue 异步队列,可以提高程序性能,但如果需要保持同步,不要使用
  • FixedThreadPool
    构造方法
    public static ExecutorService newFixedThreadPool(int nThreads) {        return new ThreadPoolExecutor(nThreads, nThreads,                                      0L, TimeUnit.MILLISECONDS,                                      new LinkedBlockingQueue());    }

可以看到,newFixedThreadPool指定了线程数,同时他只有核心线程。

线程的超时时间为0,说明核心线程即使在没有任务可执行的时候也不会被销毁(这样可让FixedThreadPool更快速的响应请求),最后的线程队列是一个LinkedBlockingQueue,但是LinkedBlockingQueue却没有参数,这说明线程队列的大小为Integer.MAX_VALUE(2的31次方减1),OK,看完参数,我们大概也就知道了FixedThreadPool的工作特点了,当所有的核心线程都在执行任务的时候,新的任务只能进入线程队列中进行等待,直到有线程被空闲出来。

特性
只有核心线程,且数目在初始化时就确定,workQueue不限大小。
例子

        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);        for (int i = 0; i < 15; i++) {              final int INDEX = i;              Runnable runnable = new Runnable() {                public void run() {                      try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("CHJ"+"run: " + INDEX);                }              };               fixedThreadPool.execute(runnable);        }  

上述例子创建了一个创建了一个拥有3个核心线程,workQueue大小为Integer最大值的线程池,for循环创建了15个任务,线程池执行时先将3个task放入核心线程,其余放到workQueue,之后核心线程执行完毕后,从队列取出task继续执行。

  • SingleThreadExecutor
    构造方法
    public static ExecutorService newSingleThreadExecutor() {        return new FinalizableDelegatedExecutorService            (new ThreadPoolExecutor(1, 1,                                    0L, TimeUnit.MILLISECONDS,                                    new LinkedBlockingQueue()));    }

可以看到,和FixedThreadPool极为类似,只不过SingleThreadExecutor只有一个核心线程
特性
只有一个核心线程
例子

public static void main(String [] args) throws InterruptedException{        ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();        for (int i = 0; i < 15; i++) {              final int INDEX = i;              Runnable runnable = new Runnable() {                public void run() {                      try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("CHJ"+"run: " + INDEX);                }              };                 singleThreadPool.execute(runnable);        }        }

上述例子创建了一个创建了一个拥有1个核心线程,workQueue大小为Integer最大值的线程池,for循环创建了15个任务,线程池执行时先将1个task放入核心线程,其余放到workQueue,之后核心线程执行完毕后,从队列取出task继续执行,每次只能执行一个任务。

  • CachedThreadPool
    构造方法
    public static ExecutorService newCachedThreadPool() {        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,                                      60L, TimeUnit.SECONDS,                                      new SynchronousQueue());    }

可以看到,CachedThreadPool没有核心线程,有Integer.MAX_VALUE个非核心线程,非核心线程60s超时,同时workQueue是SynchronousQueue,也就是支持任务异步
特性
没有核心线程,非核心线程数为Integer.MAX_VALUE,支持task异步
例子

public static void main(String [] args) throws InterruptedException{        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();        for (int i = 0; i < 15; i++) {              final int INDEX = i;              Runnable runnable = new Runnable() {                public void run() {                      try {                        Thread.sleep(2000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println("CHJ"+"run: " + INDEX);                }              };            }          cachedThreadPool.execute(runnable);    }

上述例子创建了一个创建了一个拥有0个核心线程,非核心线程为Integer.MAX_VALUE,workQueue支持异步的线程池,for循环创建了15个任务,线程池执行时先将15个task放入workQueue,从队列取出task,使用非核心线程执行任务。

  • ScheduledThreadPool
    构造方法
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {        return new ScheduledThreadPoolExecutor(corePoolSize);    }    public ScheduledThreadPoolExecutor(int corePoolSize) {        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,              new DelayedWorkQueue());    }    

可以看出,核心线程数可以指定,非核心线程数为Integer.MAX_VALUE,workQueue类型为DelayedWorkQueue
特性
可以指定任务完成后的等待时间
例子

    public static void main(String[] args) throws InterruptedException {        ScheduledExecutorService scheduledThreadPool = Executors                .newScheduledThreadPool(2);        Runnable runnable = null;        runnable = new Runnable() {            public void run() {                System.out.println("Task start"                        + format(System.currentTimeMillis()));                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println("CHJ " + "run: " + " " + format(System.currentTimeMillis()) + "thread id"                        + Thread.currentThread().getName());                System.out.println("Task end" + format(System.currentTimeMillis()));            }        };        System.out.println("Task start all"                + format(System.currentTimeMillis()));        // scheduledThreadPool.schedule(runnable, 1, TimeUnit.SECONDS);        // scheduledThreadPool.scheduleAtFixedRate(runnable, 1, 4,        // TimeUnit.SECONDS);        scheduledThreadPool.scheduleWithFixedDelay(runnable, 1, 3,                TimeUnit.SECONDS);    }    static String format(long time) {        SimpleDateFormat formatter = new SimpleDateFormat("HH时mm分ss秒");        Date date = new Date(time);        return formatter.format(date);    }
    scheduledThreadPool.schedule(runnable, 1, TimeUnit.SECONDS);    延时1s启动线程    scheduledThreadPool.scheduleAtFixedRate(runnable, 1, 4,    TimeUnit.SECONDS);    延时1s后启动线程,之后不管任务何时完成,从启动线程开始,每隔四秒尝试重新执行任务(如果任务没有执行完成,向后顺延直到任务完成)    scheduledThreadPool.scheduleWithFixedDelay(runnable, 1, 3,            TimeUnit.SECONDS);    延时1s后启动线程,之后,任务完成后等待三秒,执行下一次任务

总结

FixedThreadPool 核心线程大小固定,线程等待队列大小为整型max,没有非核心线程
SingleThreadExecutor 与FixedThreadPool极为类似,只有一个核心线程
CachedThreadPool 没有核心线程,非核心线程数Integer.MAX_VALUE,支持task异步,线程空闲60s后自动回收
ScheduledThreadPool 可以指定任务执行频率,推迟时间等等,任务调度十分方便

更多相关文章

  1. [Android] 利用Handler实现定时器功能
  2. 初学Android之小随笔2--SurfaceView
  3. android子线程创建handler
  4. Android(安卓)多线程更新控件
  5. Google Android's Gingerbread Update Coming Soon
  6. android之网络资源多线程下载
  7. android中设置进度条读取
  8. android线程池的优化
  9. Android捕获监听Home键、最近任务列表键

随机推荐

  1. 软硬结合,CDS首云AI云服务的技术实践
  2. 浅谈数据迁移
  3. Python常用数据分析库有哪些?Python学习
  4. 苹果Mac图片批量压缩重命名添加水印工具:P
  5. 信创稳妥落地,一云多芯协同是唯一答案!
  6. 20210508 字符串的格式化输出
  7. 什么是MongoDB?Python爬虫为什么使用Mongo
  8. 浅谈数据治理
  9. 详解 WebRTC 传输安全机制:一文读懂 DTLS
  10. DBA运维常用SQL脚本