假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。当T1 + T3 远大于 T2时,采用多线程技术可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。

线程池就是一个线程的容器,每次只执行额定数量的线程, 线程池作用就是限制系统中执行线程的数量。采用线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。

为什么要用线程池:

1)减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务

2)可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)

Java1.5之后,Java 提供了自己的线程池ThreadPoolExecutor类。

ThreadPoolExecutor使用简介

线程池类为java.util.concurrent.ThreadPoolExecutor,常用构造方法为:

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

corePoolSize 指的是保留的线程池大小。

maximumPoolSize 指的是线程池的最大大小。

keepAliveTime 指的是空闲线程结束的超时时间。

unit 是一个枚举,表示 keepAliveTime 的单位。

workQueue 表示存放任务的队列。

一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。

线程池的工作过程如下:

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

b. 如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列。

c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

这样的过程说明,并不是先加入任务就一定会先执行。假设队列大小为10,corePoolSize为3,maximumPoolSize 为6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务4~13被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17~20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。

下面是一个线程池使用的例子:

public class TestThreadPool {    

    public static void main(String[] args) {    

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 6, 5,TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());    

         for (int i = 1; i <= 20; i++) {     

             threadPool.execute(new ThreadPoolTask());    

             //threadPool.shutdown();
}
}
} 创建 ThreadPoolTask类: public class ThreadPoolTask implements Runnable {
public void run() {
try {
System.out.println("开始执行任务:" + attachData);
Thread.sleep(100);
}
catch(Exception e){
e.printStackTrace();
}
}
}

1、BlockingQueue 只是一个接口,常用的实现类有 LinkedBlockingQueue 和 ArrayBlockingQueue。用 LinkedBlockingQueue 的好处在于没有大小限制。这样的话,因为队列不会满,所以 execute() 不会抛出异常,而线程池中运行的线程数也永远不会超过 corePoolSize 个,keepAliveTime 参数也就没有意义了。

2、shutdown() 方法不会阻塞。调用 shutdown() 方法之后,主线程就马上结束了,而线程池会继续运行直到所有任务执行完才会停止。如果不调用 shutdown() 方法,那么线程池会一直保持下去,以便随时添加新的任务。

Java之线程池的更多相关文章

  1. 深入理解Java之线程池

    原作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本文归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则 ...

  2. Java中线程池的学习

    线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程 ...

  3. java利用线程池处理集合

    java利用线程池处理集合 2018年07月23日 17:21:19 衍夏成歌 阅读数:866   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/s ...

  4. 深入理解Java之线程池(爱奇艺面试)

    爱奇艺的面试官问 (1) 线程池是如何关闭的 (2) 如何确定线程池的数量 一.线程池销毁,停止线程池 ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown() ...

  5. Java中线程池,你真的会用吗?

    在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...

  6. [转]深入理解Java之线程池

    原文链接 原文出处: 海 子 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这 ...

  7. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  8. Java并发--线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  9. Java进阶——— 线程池的原理分析

    前言 在了解线程池之前,其实首先出现的疑问是:为什么要使用线程池,其次是了解什么是线程池,最后是如何使用线程池,带着疑问去学习. 为什么要使用 前面多线程文章中,需要使用线程就开启一个新线程,简单方便 ...

  10. Java调度线程池ScheduleExecutorService(续)

    链接 Java线程池详解(一) Java线程池详解(二) Java调度线程池ScheduleExecutorService 上面列出了最近写的关于java线程池ScheduleExecutorServ ...

随机推荐

  1. c#通过FileStream读取、写入文件

    网上找过一些FileStream读取写入文件的代码,但是都有些小问题. 于是自己整理一下,以备不时之需.说明一下,以下代码我都运行过. 1.FileStream读取文件 // FileStream读取 ...

  2. eclipse项目引用项目方法

    在Java Build Path中将被引用项目Add加入到引用项目中. 在Deployment Assembly中将被引入项目Add加到配置项中. 这样在项目发布到tomcat中时被引入项目会被打成j ...

  3. atitit.thumb生成高质量缩略图 php .net c++ java

    atitit.java thumb生成高质量缩略图 php .net c++ 1. 图像缩放(image scaling)---平滑度(smoothness)和清晰度(sharpness) 1 2.  ...

  4. Atitit.多媒体区----web视频格式的选择总结

    Atitit.多媒体区----web视频格式的选择总结 1. 因为现阶段不同的浏览器支持的视频格式是不同的 1 2. 各浏览器Html5 Video支持的影音格式: 2 3. 解决方案是什么?Flas ...

  5. Django Model获取指定列的数据

    model一般都是有多个属性的,但是很多时候我们又只需要查询特定的某一个,这个时候可以用到values和values_list 利用values查询 from attendence.models im ...

  6. 手把手教做Excel直方图

    手把手教做Excel直方图 2017-10-05  作者:ExcelHome  阅读:71968次   直方图是用于展示数据的分组分布状态的一种图形,用矩形的宽度和高度表示频数分布,通过直方图,用户可 ...

  7. Apache Rewrite 拟静态

    mod_rewrite是Apache的一个非常强大的功能,它可以实现伪静态页面.一些防盗链就是通过该方法做到的. 00x1 启动rewrite引擎 00x2 如何启用apache rewrite? 0 ...

  8. [uboot]MLO和uboot-spl.bin, uboot.img和uboot.bin

    前段时间使用TI的am4378芯片,发现系统在SD卡启动的时候,启动文件使用的是MLO和uboot.img:而Norflash和eMMC启动的时候使用的是 uboot-spl.bin和uboot.bi ...

  9. Android——Android Studio的一些小技巧(转)

    ndroid课程---Android Studio的一些小技巧   APK瘦身 在Android Studio中我们可以开启混淆,和自动删除没有Resources文件,来达到给APP瘦身的目的,这对于 ...

  10. PHP——简单的表单提交

    <body> <form name="" method="post" action="CHULI.php"> < ...