一,简述线程池:

线程池是如何工作的:一系列任务出现后,根据自己的线程池安排任务进行。

如图:

 

线程池的好处:

  1. 重用线程池中的线程,避免因为线程的创建和销毁所带来的性能开销。
  2. 能有效控制线程池的最大并发数,避免大量的线程之间因互相抢占系统资源而导致的阻塞现象。
  3. 能对线程进行简单的管理。并提供定时执行以及指定间隔循环执行等功能。

线程池的具体实现为ThreadPoolExeutor,其接口为Executor

ThreadPoolExecutor提供了一系列的参数用于配置线程池。

   public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}

参数含义如下:

  1. corePoolSize :线程池核心线程数,默认情况下,核心线程会在线程池中一直存活,即使他们处于闲置状态。其有一个allowCoreThreadTimeOut属性如果设置为true,那么核心线程池会有超时策略。超时的时长为第三个参数  keepAliveTime 。如果超时,核心线程会被终结。
  2. maxmumPoolSize: 线程池所能容忍的最大线程数,当活动线程数达到这个数值后,后续的新任务会被阻塞。
  3. keepAliveTime:非核心线程闲置时的超时时长,超过这个时长就会被非核心线程会被回收。这个参数如同第一个参数,如果设置相关属性后也会作用于核心线程。、
  4. unit:指定keepAliveTime的参数时间单位。这是一个枚举,常用的有MILLISECONDS(毫秒)、SECONDS(秒)等
  5. workQueue:线程池的任务队列,通过execute()方法(执行方法)提交的Runable对象会存储在这个参数中。
  6. threadFactory:线程工厂,为线程池提供创建新线程的功能。

其执行任务时大致遵顼如下规则:

  1. 如果线程达到核心线程数量,那么回直接启动一个核心线程。
  2. 线程未达到核心线程的数量,任务会被插入到任务队列(workQueue)排队。
  3. 如果任务队列已满导致步骤二无法插入到任务队列,那么开启一个非核心线程执行。
  4. 如果步骤三的线程数量达到线程池规定数目(maxmumPoolSize),那么拒绝执行此任务。

二,线程池的相关类结构解析

看一下线程池的类结构图:

  

  说以下这几点:

     这是一个抽象工厂模式!

  Executor和Executors的区别:

  Executor仅仅是一个接口,其只有一个方法,execute()方法(执行方法)。

public interface Executor {

    void execute(Runnable command);
}

   而Executors是一个没有继承任何类的方法,其作为一个工厂方法类,用于创建形形色色的线程池等对象。如:FixedThreadPool、defaultThreadFactory(下面会具体讲),而这些具体的线程池方案(FixedThreadPool)亦或者自定义的线程池方案(ThreadPoolExeutor)都是来自ExecutorService接口,这个接口也是继承于Executor接口。通过类结构图可以很清楚的看到。

如,Executors生产出ExecutorService对象,源码如下

public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}

 说到工厂模式,ThreadPoolExeutor的参数threadFactory是一个接口,仅有newThread方法,代码如下

  

public interface ThreadFactory {

    Thread newThread(Runnable r);
}

其作用和executor接口类似,体现面向接口编程思想。其中例如如下两个方法,是工厂方法类Executors所生成的ThreadFactory对象。

 public static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
} public static ThreadFactory privilegedThreadFactory() {
return new PrivilegedThreadFactory();
}
 

 defaultThreadFactory是这样创建线程的,如果要自定义不妨参照一下。

  

static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix; DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
} public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}

三 具体线程池的使用

说了那么多,要具体看看系统提供的线程池,主要是这四个:

  1. FixedTreadPool. fixed有稳固的含义,通过工厂方法类Executors的newFixedThreadPool方法创建。它是线程数量固定的线程池,仅有核心线程且没有超时策略,所以线程不会被回收。这意味着它能够快速的响应外界请求。

  例子:这里设置了4个runnable和2个核心线程。

  Runnable runnable = new Runnable() {
@Override
public void run() {
Log.d("hello","sleep前");
SystemClock.sleep(3000);
Log.d("hello", "sleep后");
}
};
...... ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(runnable);
executorService.execute(runable1);
executorService.execute(runable2);
executorService.execute(runable3);

输出如下,

06-24 15:49:47.962 12462-12497/? D/hello: sleep1前
06-24 15:49:47.962 12462-12496/? D/hello: sleep前
06-24 15:49:50.962 12462-12497/com.example.hang.myapplication D/hello: sleep1后
06-24 15:49:50.962 12462-12497/com.example.hang.myapplication D/hello: sleep2前
06-24 15:49:50.972 12462-12496/com.example.hang.myapplication D/hello: sleep后
06-24 15:49:50.972 12462-12496/com.example.hang.myapplication D/hello: sleep3前
06-24 15:49:53.962 12462-12497/com.example.hang.myapplication D/hello: sleep2后
06-24 15:49:53.972 12462-12496/com.example.hang.myapplication D/hello: sleep3后

可以看到,每次仅有两个线程去执行,当其中一个执行完毕后才轮到下一个。
当 核心线程数量改为 4 时,则会一次性执行完这4个runnable。

  1. CachedThreadPool.它是一种线程数量不定的线程池,只有非核心线程,可以简单理解为最大线程数是无限大的。CachedThreadPool的任务队列相当于一个空集合,这导致任何任务都会被立即执行,比较适合做一些大量的耗时较少的任务。

 例子,修改为将上述的  ExecutorService executorService = Executors.newFixedThreadPool(2);替换为

ExecutorService executorService = Executors.newCachedThreadPool();,输出如下,一次性执行4个线程,且线程顺序不定。
06-24 15:53:08.582 16801-16873/com.example.hang.myapplication D/hello: sleep2前
06-24 15:53:08.582 16801-16872/com.example.hang.myapplication D/hello: sleep1前
06-24 15:53:08.582 16801-16871/com.example.hang.myapplication D/hello: sleep前
06-24 15:53:08.582 16801-16875/com.example.hang.myapplication D/hello: sleep3前
06-24 15:53:11.582 16801-16873/com.example.hang.myapplication D/hello: sleep2后
06-24 15:53:11.582 16801-16872/com.example.hang.myapplication D/hello: sleep1后
06-24 15:53:11.582 16801-16871/com.example.hang.myapplication D/hello: sleep后
06-24 15:53:11.582 16801-16875/com.example.hang.myapplication D/hello: sleep3后
  1. ScheduledThreadPool.Scheduled有 “预定的” 意思。核心线程池的数量书固定的且非核心线程池是没有限制的,非核心线程池被闲置时会被立即回收。主要用于执行定时任务和具有固定周期的重复任务。

  例子:这里是延迟2000ms后开始执行

 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
scheduledExecutorService.schedule(runnable,2000, TimeUnit.MILLISECONDS);
scheduledExecutorService.schedule(runable1, 2000, TimeUnit.MILLISECONDS);
scheduledExecutorService.schedule(runable2, 2000, TimeUnit.MILLISECONDS);
scheduledExecutorService.schedule(runable3, 2000, TimeUnit.MILLISECONDS);

  例子:延迟10ms后开始每1000ms执行一次runnable。

 scheduledExecutorService.scheduleAtFixedRate(runnable,10,1000,TimeUnit.MILLISECONDS);
  1. SingleThreadExecutor.只有一个核心线程,所以确保所有的任务都是在一个线程里顺序执行。把所有的任务都放到一个线程,这样有一个好处是不需要处理线程同步问题。

这里就不做例子了,就是4个排着队依次执行,且不会乱序。

  

06-24 16:05:02.782 32057-32125/com.example.hang.myapplication D/hello: sleep前
06-24 16:05:05.782 32057-32125/com.example.hang.myapplication D/hello: sleep后
06-24 16:05:05.782 32057-32125/com.example.hang.myapplication D/hello: sleep1前
06-24 16:05:08.782 32057-32125/com.example.hang.myapplication D/hello: sleep1后
06-24 16:05:08.782 32057-32125/com.example.hang.myapplication D/hello: sleep2前
06-24 16:05:11.782 32057-32125/com.example.hang.myapplication D/hello: sleep2后
06-24 16:05:11.782 32057-32125/com.example.hang.myapplication D/hello: sleep3前
06-24 16:05:14.782 32057-32125/com.example.hang.myapplication D/hello: sleep3后

java/android线程池详解的更多相关文章

  1. java - jdk线程池详解

    线程池参数详解 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUni ...

  2. Java多线程-----线程池详解

    1. 线程池的实现原理 提交一个任务到线程池中,线程池的处理流程如下: 判断线程池里的核心线程是否都在执行任务,如果不是(核心线程空闲或者还有核心线程没有被创建)则创建一个新的工作线程来执行任务.如果 ...

  3. Java线程池详解(二)

    一.前言 在总结了线程池的一些原理及实现细节之后,产出了一篇文章:Java线程池详解(一),后面的(一)是在本文出现之后加上的,而本文就成了(二).因为在写完第一篇关于java线程池的文章之后,越发觉 ...

  4. 三、VIP课程:并发编程专题->01-并发编程之Executor线程池详解

    01-并发编程之Executor线程池详解 线程:什么是线程&多线程 线程:线程是进程的一个实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系 ...

  5. nginx源码分析线程池详解

    nginx源码分析线程池详解 一.前言     nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...

  6. Java 并发编程 | 线程池详解

    原文: https://chenmingyu.top/concurrent-threadpool/ 线程池 线程池用来处理异步任务或者并发执行的任务 优点: 重复利用已创建的线程,减少创建和销毁线程造 ...

  7. Java线程池详解

    一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...

  8. Java多线程之线程池详解

    前言 在认识线程池之前,我们需要使用线程就去创建一个线程,但是我们会发现有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因 ...

  9. Java线程池详解(一)

    一.线程池初探 所谓线程池,就是将多个线程放在一个池子里面(所谓池化技术),然后需要线程的时候不是创建一个线程,而是从线程池里面获取一个可用的线程,然后执行我们的任务.线程池的关键在于它为我们管理了多 ...

随机推荐

  1. python 对数函数

    from math import logfrom math import e print e #自然对数print log(e) #log函数默认是以e为底print log(100,10) #以10 ...

  2. 清除Xcode缓存和存档文件

    XCode4.2    finder中找到   /Users/Library/Developer/Xcode    (注:Library资源库是隐藏的文件夹) 里面有DerivedData和Snaps ...

  3. Linux makefile教程之书写命令四[转]

    书写命令———— 每 条规则中的命令和操作系统Shell的命令行是一致的.make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟 在依赖规则后面的分号后的.在命令 ...

  4. SQL0668N 由于表 "db2inst1.test" 上的原因代码 "3",所以不允许操作(解因为LOAD引起的LOAD暂挂状态锁)

    DB2解因为LOAD引起的LOAD暂挂状态锁   一般解锁命名是,SET INTEGRITY FOR temp_test IMMEDIATE CHECKED   但是load暂挂状态是解不了的,可以l ...

  5. sqlplus常用命令

    原文 sqlplus常用命令 desc 表名            显示表的结构 show user           显示当前连接用户 show error            显示错误 sho ...

  6. Windows Server 2012 R2 设置 smtp 服务器

    Windows Server 2012/2012 R2:安装和配置 SMTP 服务器 安装 SMTP 服务器 以下是安装 SMTP 服务器功能的步骤: 打开“服务器管理器”:单击键盘上的 Window ...

  7. Drupal 7.23:函数module_invoke_all()注释

    /** * Invokes a hook in all enabled modules that implement it. * * All arguments are passed by value ...

  8. 【转】linux之e2label命令

    转自:http://www.th7.cn/system/lin/201311/46743.shtml 前言 e2label命令,用于获取或设置ext2.ext3文件系统对应的分区的卷标. 卷标:简单来 ...

  9. DOM笔记(六):怎么进行JQuery扩展?

    一.全局函数的扩展 全局函数是将独立的函数添加到JQuery的命名空间中区.在使用的时候,可以通过$.fucnName(param)或者jQuery.funcName(param)方式进行调用. 1. ...

  10. IOS平台设计规范

    一.UI的控件概述: 1.框架UI的元素分为4类: A:栏:状态栏目和导航栏的结合体; B:内容视图:应用显示的内容信息,包括相关的交互行为,例如滚屏.插入.删除等操作进行排序; C:控制元素:产品行 ...