1、什么是线程池?

  简单粗暴的理解就是:装着一个或多个线程的容器,我们称这个容器为线程池。

  在现实世界中,有着各种各样的“池”,例如游泳池、花池等等。那花池来说,里面种满了各种各样的鲜花,花池本身要做的就是提供一片空地,里面的鲜花是园丁来种植、浇水。不同于花池,线程池不仅仅需要提供一个可以装线程的容器,同时还要承担起管理容器里中线程的职责(例如,新建线程、使用线程等)。

  一个简单的线程池应该至少包含下面4个部分:

    (1)线程池管理器:创建、销毁并管理线程池,将工作线程放入线程池中

    (2)工作线程:一个可以循环执行任务的线程,在没有任务时进行等待

    (3)任务队列:将没有处理的任务放在任务队列中,提供一种缓冲机制

    (4)任务接口:主要用来规定任务的的入口、任务完成后的收尾工作、任务的执行状态等,工作线程通过该接口调度任务的执行

  下面举一个简单的例子来理解线程池的工作:

    将线程比作一个机器人,一个线程池就是有很多机器人的工厂,工厂通过新建机器人、分配任务给机器人等方式管理者工厂中的所有机器人。初始时,工厂中并没有机器人。当工厂接到第一个任务时,工厂的管理人员首先新建机器人1号,然后再将任务分配给机器人1号,机器人1号收到任务的命令后就开始工作了。紧接着,工厂接到了第二个任务,管理人员又新建了机器人2号,将第二个任务分配给了机器人2号。当工厂再次接到新的任务时,重复前面的过程。然而,工厂不可能无限制地新建机器人:新建机器人也是需要材料和消耗资源的,资源是有限的;当有新的任务时,前面新建的机器人可能已经完成了交给它的任务而处于空闲状态,因此可以将新的任务分配给处于休息状态的机器人。当工厂中所有的机器人都处于工作状态时,又来了新的任务,怎么办呢?于是,工厂管理者设置了一个任务等候区,新来的任务按顺序在等候区排队。当有机器人完成了任务时,从任务队列中取出一个任务,分配给空闲的机器人,让机器人重新处于工作状态。

2、为什么要使用线程池?

  从前面工厂的例子中可以看出,线程池为我们带来了以下好处:

    (1)分摊创建线程的开销,加快对请求的响应速度。接到一个任务时,新建了一个线程用于完成任务。当任务完成后,线程处于空闲状态,后面再有新的任务时,不必再新建线程,处于空闲状态的线程可以直接投入工作,省去了新建线程了过程,加快了对请求的响应速度。由于对线程实现了重用,新建线程的开销就被分摊到了多个任务上,线程被重用的次数越多,平均分摊到每个任务中的线程创建的开销就越少。

    (2)解决了资源不足的问题。线程是需要资源的,而资源又是有限的,通过控制线程的数目,避免出现资源不足的问题。

3、如何使用线程池?

  线程池有着上面的优势,可以自己编码实现一个线程池。然而,编码实现线程池本身就是一项工作量不小的任务,而我们的工作重心是要完成实际的业务。同时,自己编码实现的线程池的正确性、可靠性与稳定性难以保证。于是,大师Doug Lea编写并开源了一个并发程序的代码库,在JDK 1.5之后已加入JDK的豪华套餐,为 java.util.concurrent包。

  在Java中,线程池类为java.util.concurrent.ThreadPoolExecutor,可以通过该类创建我们需要的线程池:

     public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)

参数说明:

  corePoolSize : 线程池维护线程的数量(the number of threads to keep in the pool, even if they are idle.)

  maximumPoolSize : 线程池维护线程的最大数量(the maximum number of threads to allow in the pool.)

  keepAliveTime : 线程池中的线程允许的最大空闲时间(when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.)

  unit : 参数keepAliveTime的时间单位 (the time unit for the keepAliveTime argument.)

  workQueue : 任务缓冲队列(the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.)

  handler : 对拒绝任务的处理策略(the handler to use when execution is blocked because the thread bounds and queue capacities are reached.)

  通过上面的构造函数,可以构造一个线程池对象threadPool。在Java中,一个任务就是一个Runnable类的对象,具体的业务处理逻辑在该对象的run()方法中实现。通过threadPoool.execute(Runnable)方法,任务被提交到了线程池中并执行。

  【代码实例】

  任务类:

 package com.code.threadpool;

 import java.io.Serializable;

 public class ThreadPoolTask implements Runnable, Serializable {

     private static final long serialVersionUID = 1L;

     private Object threadPoolTaskData;

     ThreadPoolTask(Object tasks) {
this.threadPoolTaskData = tasks;
} public void run() {
System.out.println("start ..." + threadPoolTaskData);
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end ..." + threadPoolTaskData);
threadPoolTaskData = null;
} }

线程池测试类:

 package com.code.threadpool;

 import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; public class ThreadPoolTest { /**
* 核心线程数量,线程池维护线程的最少数量
*/
private static final int corePoolSize = 2; /**
* 线程池维护线程的最大数量
*/
private static final int maxPoolSize = 4; /**
* 线程池维护线程所允许的空闲时间
*/
private static final int keepAliveTime = 3; /**
* 线程池所使用的缓冲队列的大小
*/
private static final int workQueueSize = 3; /**
* 线程执行任务后sleep的时间,sleep是为了便于观察程序的运行结果
*/
private static final int produceTaskSleepTime = 2; /**
* 任务的最大数量
*/
private static final int produceTaskMaxNumber = 10; /**
* 任务名称的前缀
*/
private static final String taskNamePrefix = "task@"; public static void main(String[] args) { ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize,
maxPoolSize, keepAliveTime, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(workQueueSize),
new ThreadPoolExecutor.DiscardOldestPolicy()); for (int i = 0; i < produceTaskMaxNumber; i++) {
String taskName = taskNamePrefix + (i + 1);
System.out.println(String.format("put %s", taskName)); System.out.println("--- before put " + taskName
+ ", active thread count: " + threadPool.getActiveCount());
ThreadPoolTask task = new ThreadPoolTask(taskName);
threadPool.execute(task);
System.out.println("--- after put " + taskName
+ ", active thread count: " + threadPool.getActiveCount()); try {
Thread.sleep(produceTaskSleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }

【运行结果】

 put task@1
--- before put task@1, active thread count: 0
--- after put task@1, active thread count: 0
start ...task@1
put task@2
--- before put task@2, active thread count: 1
--- after put task@2, active thread count: 1
start ...task@2
put task@3
--- before put task@3, active thread count: 2
--- after put task@3, active thread count: 2
put task@4
--- before put task@4, active thread count: 2
--- after put task@4, active thread count: 2
put task@5
--- before put task@5, active thread count: 2
--- after put task@5, active thread count: 2
put task@6
--- before put task@6, active thread count: 2
--- after put task@6, active thread count: 2
start ...task@6
put task@7
--- before put task@7, active thread count: 3
--- after put task@7, active thread count: 3
start ...task@7
put task@8
--- before put task@8, active thread count: 4
--- after put task@8, active thread count: 4
put task@9
--- before put task@9, active thread count: 4
--- after put task@9, active thread count: 4
put task@10
--- before put task@10, active thread count: 4
--- after put task@10, active thread count: 4
end ...task@1
start ...task@8
end ...task@2
start ...task@9
end ...task@6
start ...task@10
end ...task@7
end ...task@8
end ...task@9
end ...task@10

参考资料:

  1、http://blog.itpub.net/9399028/viewspace-1852029/

  2、http://blog.csdn.net/newchenxf/article/details/51996950

  3、http://uule.iteye.com/blog/1123185

  4、http://www.cnblogs.com/dolphin0520/p/3932921.html

  5、https://segmentfault.com/a/1190000007120459

本文为原创文章,转载请注明出处:http://www.cnblogs.com/acode/p/6385880.html

Java线程池(一):初识的更多相关文章

  1. Java 线程池框架核心代码分析--转

    原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...

  2. Java线程池使用说明

    Java线程池使用说明 转自:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极 ...

  3. (转载)JAVA线程池管理

    平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...

  4. Java线程池的那些事

    熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor.大家可能了解到它的原理,甚至看过它的源码:但 ...

  5. 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 执行一个异步任务你还只是如下 ...

  6. Java线程池的几种实现 及 常见问题讲解

    工作中,经常会涉及到线程.比如有些任务,经常会交与线程去异步执行.抑或服务端程序为每个请求单独建立一个线程处理任务.线程之外的,比如我们用的数据库连接.这些创建销毁或者打开关闭的操作,非常影响系统性能 ...

  7. Java线程池应用

    Executors工具类用于创建Java线程池和定时器. newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程.在任意点,在大多数 nThread ...

  8. Java线程池的原理及几类线程池的介绍

    刚刚研究了一下线程池,如果有不足之处,请大家不吝赐教,大家共同学习.共同交流. 在什么情况下使用线程池? 单个任务处理的时间比较短 将需处理的任务的数量大 使用线程池的好处: 减少在创建和销毁线程上所 ...

  9. Java线程池与java.util.concurrent

    Java(Android)线程池 介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行 ...

  10. [转 ]-- Java线程池使用说明

    Java线程池使用说明 原文地址:http://blog.csdn.net/sd0902/article/details/8395677 一简介 线程的使用在java中占有极其重要的地位,在jdk1. ...

随机推荐

  1. cogs468 [NOI2010]超级钢琴

    http://cogs.pro:8080/cogs/problem/problem.php?pid=468 emmmmmm 今天考试爆炸顺便切了这题 这题我肯定不会啦然后看一sol.. 固定一个右端点 ...

  2. Flutter - 创建横跨所有页面的侧滑菜单

    前一篇博客讲到了如何创建侧滑菜单,但是再实际使用过程中,会发现,这个策划菜单只能在首页侧滑出来. 当导航到其他页面后,侧滑就不管用了.这也有点不符合良好的用户体验设计.Google Play就是很好的 ...

  3. POM.XML文档汉化

    #class_issueManagement project 所述 <project> 元素是描述符的根.下表列出了所有可能的子元素. modelVersion:String:声明此POM ...

  4. hdu2544最短路(dijkstra)

    传送门 dijkstra #include<bits/stdc++.h> using namespace std; const int INF=0x3f3f3f3f; ; int dist ...

  5. jenkins 多任务串行执行

    摘要 今天在新创建自动化部署项目的时候遇到了一个问题:我们的项目是maven聚合的所以在构建maven项目的时候要从parent开始build,但是这样会造成一个问题,我每次添加此parent项目下的 ...

  6. Linux命令的那些事(三)

    回顾linux命令那些事,前面大致总结了常用的Linux命令 回顾Linux命令那些事(一) clear/mkdir/rmdir/ls/rm/pwd/cd/touch/tree/man/--help ...

  7. LeetCode 192. Word Frequency

    分析 写bash,不太会啊…… 难度 中 来源 https://leetcode.com/problems/word-frequency/ 题目 Write a bash script to calc ...

  8. PHP核心技术——接口

    接口: 接口这样描述自己:对于实现我的所有类,看起来都应该像我现在这个样子 接口含义:采用一个特定接口的所有代码都知道对于那个接口会调用什么方法. interface mobile{ public f ...

  9. 输入一个URL到页面呈现其中发生的过程-------http过程详解

    在我们点击一个网址,到它能够呈现在浏览器中,展示在我们面前,这个过程中,电脑里,网络上,究竟发生了什么事情. 服务器启动监听模式 那我们就开始了,故事其实并不是从在浏览器的地址栏输入一个网址,或者我们 ...

  10. gulp-babel 阻止了js文件编译的进程?

    现象 :   编译打包的js没有输出到目标文件夹里,只是单单的生成了一个目标目录,目录里没有文件 解决方法:gulp-babel ^8.0.0 使用了 ^7.0.1的 依赖插件.统一gulp-babe ...