一、线程池的作用

  平时的业务中,如果要使用多线程,那么我们会在业务开始前创建线程,业务结束后,销毁线程。但是对于业务来说,线程的创建和销毁是与业务本身无关的,只关心线程所执行的任务。因此希望把尽可能多的cpu用在执行任务上面,而不是用在与业务无关的线程创建和销毁上面。而线程池则解决了这个问题。

  线程池的作用:线程池作用就是限制系统中执行线程的数量。根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果,从而避免平凡的创建和销毁线程带来的系统开销也有效的规避了因为创建的线程过多而耗尽系统资源导致服务器宕机。使用Runtime.getRuntime().availableProcessors();设置线程数量。

二、 java并发包提供的线程池 Executors类

  A、newFixedThreadPool  用来创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

ExecutorService fixedThreadPool =Executors.newFixedThreadPool(1);

  1. public static ExecutorService newFixedThreadPool(int nThreads) {
  2. //参数详解 第一个参数核心线程数,线程池在实例化的时候初始化时线程数
  3. //第二个:该线程池最大线程数
  4. //第三个:线程空闲时间(0L表示没有空闲时间即没有使用就会被回收)
  5. //第四个:空闲时间单位
  6. //第五个:LinkedBlockingQueue 无界队列 ,将没有线程处理的任务加入该队列中
  7. return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
  8. }

  B、newSingleThreadExecutor 用来创建一个单线程化的线程池,它只用唯一的工作线程来执行任务,一次只支持一个,所有任务按照指定的顺序执行

    ExecutorService fixedThreadPool = Executors.newSingleThreadExecutor();

  1. public static ExecutorService newSingleThreadExecutor() {
  2. //参数详解 第一个参数核心线程数,线程池在实例化的时候初始化时线程数
  3. //第二个:该线程池最大线程数
  4. //第三个:线程空闲时间(0L表示没有空闲时间即没有使用就会被回收)
  5. //第四个:空闲时间单位
  6. //第五个:LinkedBlockingQueue 无解队列 ,将没有线程处理的任务加入该队列中
  7. return new FinalizableDelegatedExecutorService
  8. (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
  9. }

  C、newCachedThreadPool  用来创建一个可缓存线程池,该线程池没有长度限制,对于新的任务,如果有空闲的线程,则使用空闲的线程执行,如果没有,则新建一个线程来执行任务。如果线程池长度超过处理需要,可灵活回收空闲线程。

ExecutorService fixedThreadPool = Executors.newCachedThreadPool();

  1. public static ExecutorService newCachedThreadPool() {
  2. //参数详解 第一个参数核心线程数,线程池在实例化的时候初始化时线程数
  3. //第二个:Integer.MAX_VALUE 不限制该线程池的线程数
  4. //第三个:线程空闲时间(60L 表示线程空闲60秒之后被回收)
  5. //第四个:空闲时间单位 SECONDS 秒
  6. //第五个:SynchronousQueue 无容量队列 ,将任务直接提交给线程处理自身不存储任务
  7. return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
  8. }

  D、newScheduledThreadPool 用来创建一个定长线程池,并且支持定时和周期性的执行任务

    ScheduledExecutorService executorsScheduled=Executors.newScheduledThreadPool(2);

  1. public ScheduledThreadPoolExecutor(int corePoolSize) {
  2. //参数详解 第一个参数核心线程数,线程池在实例化的时候初始化时线程数
  3. //第二个:Integer.MAX_VALUE 不限制该线程池的线程数
  4. //第三个:线程空闲时间(0 表示线程空闲0秒之后被回收)
  5. //第四个:空闲时间单位 SECONDS 秒
  6. //第五个:DelayedWorkQueue 延时队列
  7. super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,new DelayedWorkQueue());
  8. }

使用 newScheduledThreadPool实现定时器

  1. package com.jalja.org.thread.executors;
  2. import java.util.concurrent.Executors;
  3. import java.util.concurrent.ScheduledExecutorService;
  4. import java.util.concurrent.ScheduledFuture;
  5. import java.util.concurrent.TimeUnit;
  6. public class NewScheduledThreadPoolTest {
  7. public static void main(String[] args) {
  8. Runnable runnable=new ScheduledThread();
  9. //实现定时器
  10. ScheduledExecutorService executorsScheduled=Executors.newScheduledThreadPool(2);
  11. //runnable 需要执行的任务 1:初始化时间(初始化延迟1秒后执行) 3:轮询时间(每隔3秒执行)
  12. //TimeUnit.SECONDS:时间单位
  13. ScheduledFuture<?> scheduledFuture= executorsScheduled.scheduleWithFixedDelay(runnable, 1,3, TimeUnit.SECONDS);
  14. System.out.println("scheduledFuture:"+scheduledFuture);
  15. }
  16. }
  17. class ScheduledThread implements Runnable{
  18. public void run() {
  19. System.out.println(Thread.currentThread().getName() +"=>开始");
  20. try {
  21. Thread.sleep(1000);
  22. } catch (InterruptedException e) {
  23. // TODO Auto-generated catch block
  24. e.printStackTrace();
  25. }
  26. System.out.println(Thread.currentThread().getName() +"=>结束");
  27. }
  28. }

 线程池中提交任务的两种方式:

execute()方法:该方法是 ExecutorService 接口的父类(接口)方法,该接口只有这一个方法。

  1. public interface Executor {
  2. void execute(Runnable command);
  3. }

submit()方法:该方法是ExecutorService 接口的方法。

  1. public interface ExecutorService extends Executor {
  2.   ...
  3.   <T> Future<T> submit(Callable<T> task);
  4.  
  5.   <T> Future<T> submit(Runnable task, T result);
  6.  
  7.   Future<?> submit(Runnable task);
  8.   ...
  9. }

从上面的源码以及讲解可以总结execute()和submit()方法的区别:

  1. 接收的参数不一样;

  2. submit()有返回值,而execute()没有;

三、自定义线程池

  在Java线程池中的newCachedThreadPool,newFixedThreadPool,newSingleThreadExecutor,newScheduledThreadPool这四个线程池在底层都是调用了ThreadPoolExecutor()这个构造方法。若Executors这个类无法满足我们的需求的时候,可以自己创建自定义的线程池。
ThreadPoolExecutor类的定义如下

  1. public ThreadPoolExecutor(int corePoolSize,//核心线程数--线程池初始化创建的线程数量
  2. int maximumPoolSize,//最大线程数,线程池中能创建的最大线程数
  3. long keepAliveTime,//线程存活时间
  4. TimeUnit unit,//线程存货时间单位
  5. BlockingQueue<Runnable> workQueue,//一个阻塞队列
  6. ThreadFactory threadFactory//拒绝策略
  7. ) {……}

自定义线程池使用有界队列(ArrayBlockingQueue 、LinkedBlockingQueue )

  若有新的任务需要执行,如果线程池实际线程数小于corePoolSize核心线程数的时候,则优先创建线程。若大于corePoolSize时,则会将多余的线程存放在队列中,若队列已满,且最请求线程小于maximumPoolSize的情况下,则自定义的线程池会创建新的线程,若队列已满,且最请求线程大于maximumPoolSize的情况下,则执行拒绝策略,或其他自定义方式。

  1. package com.jalja.org.thread.executors;
  2.  
  3. import java.util.concurrent.LinkedBlockingQueue;
  4. import java.util.concurrent.ThreadPoolExecutor;
  5. import java.util.concurrent.TimeUnit;
  6.  
  7. public class ExecutorsTest {
  8. public static void main(String[] args) {
  9. ThreadPoolExecutor test=new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(2));
  10. test.execute(new ExecutorsTest().new ThreadTest());
  11. test.execute(new ExecutorsTest().new ThreadTest());
  12. test.execute(new ExecutorsTest().new ThreadTest());
  13. test.execute(new ExecutorsTest().new ThreadTest());
  14. test.execute(new ExecutorsTest().new ThreadTest());
  15. test.shutdown();
  16. }
  17. class ThreadTest implements Runnable{
  18. public void run() {
  19. System.out.println(Thread.currentThread().getName());
  20. try {
  21. Thread.sleep(5000);
  22. } catch (InterruptedException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }
  27. }

结果:

  1. Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.jalja.org.thread.executors.ExecutorsTest$ThreadTest@70dea4e rejected from java.util.concurrent.ThreadPoolExecutor@5c647e05[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
  2. at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
  3. at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
  4. at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
  5. at com.jalja.org.thread.executors.ExecutorsTest.main(ExecutorsTest.java:17)
  6. pool-1-thread-1
  7. pool-1-thread-2
  8. pool-1-thread-1
  9. pool-1-thread-2

看结果可知有一个任务是没有执行直接抛出异常的。队列已满,且最请求线程大于maximumPoolSize的情况下,则执行拒绝策略,这里使用的是——AbortPolicy:直接抛出异常,系统正常工作(默认的策略)。

自定义线程池使用无界队列:

  对于无界队列除非系统资源耗尽,否则无界队列不存在任务入队失败的情况,若系统的线程数小于corePoolSize时,则新建线程执行corePoolSize,当达到corePoolSize后,则把多余的任务放入队列中等待执行若任务的创建和处理的速速差异很大,无界队列会保持快速增长,直到耗尽系统内存为之,对于无界队列的线程池maximumPoolSize并无真实用处。

四、拒绝策略

JDK提供策略:

1.AbortPolicy:直接抛出异常,系统正常工作。(默认的策略)

  1. package com.jalja.org.thread.executors;
  2.  
  3. import java.util.concurrent.BlockingQueue;
  4. import java.util.concurrent.LinkedBlockingQueue;
  5. import java.util.concurrent.RejectedExecutionException;
  6. import java.util.concurrent.ThreadPoolExecutor;
  7. import java.util.concurrent.TimeUnit;
  8.  
  9. public class ExecutorsTest {
  10. public static void main(String[] args) {
  11. BlockingQueue<Runnable> f=new LinkedBlockingQueue<Runnable>(2);
  12. ThreadPoolExecutor test=new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS,f);
  13. try {
  14. test.execute(new ExecutorsTest().new ThreadTest());
  15. test.execute(new ExecutorsTest().new ThreadTest());
  16. test.execute(new ExecutorsTest().new ThreadTest());
  17. test.execute(new ExecutorsTest().new ThreadTest());
  18. test.execute(new ExecutorsTest().new ThreadTest());
  19. } catch (RejectedExecutionException e) {
  20. e.printStackTrace();
  21. System.out.println("超过有界队列的数据记录日志");
  22. }
  23. test.shutdown();
  24. }
  25. class ThreadTest implements Runnable{
  26. public void run() {
  27. System.out.println(Thread.currentThread().getName());
  28. try {
  29. Thread.sleep(5000);
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }
  35. }

2.CallerRunsPolicy:只要线程池未关闭,该策略直接在调用者线程中执行,运行当前被丢弃的任务。
3.DiscardOrderstPolicy:丢弃最老的请求,尝试再次提交当前任务。
4.丢弃无法处理的任务,不给于任何处理。

自定义策略:需要实现RejectedExecutionHandler接口

  1. package com.jalja.org.thread.executors;
  2.  
  3. import java.util.concurrent.BlockingQueue;
  4. import java.util.concurrent.LinkedBlockingQueue;
  5. import java.util.concurrent.RejectedExecutionException;
  6. import java.util.concurrent.RejectedExecutionHandler;
  7. import java.util.concurrent.ThreadPoolExecutor;
  8. import java.util.concurrent.TimeUnit;
  9.  
  10. public class ExecutorsTest {
  11. public static void main(String[] args) {
  12. BlockingQueue<Runnable> f=new LinkedBlockingQueue<Runnable>(2);
  13. ThreadPoolExecutor test=new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS,f, new MyRejected());
  14. test.execute(new ExecutorsTest().new ThreadTest());
  15. test.execute(new ExecutorsTest().new ThreadTest());
  16. test.execute(new ExecutorsTest().new ThreadTest());
  17. test.execute(new ExecutorsTest().new ThreadTest());
  18. test.execute(new ExecutorsTest().new ThreadTest());
  19. test.shutdown();
  20. }
  21. class ThreadTest implements Runnable{
  22. public void run() {
  23. System.out.println(Thread.currentThread().getName());
  24. try {
  25. Thread.sleep(5000);
  26. } catch (InterruptedException e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }
  31. }
  32. class MyRejected implements RejectedExecutionHandler{
  33. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  34. System.out.println("执行异常的任务加入日志");
  35. }
  36. }

java 线程之executors线程池的更多相关文章

  1. java多线程之 Executors线程池管理

    1. 类 Executors 此类中提供的一些方法有: 1.1 public static ExecutorService newCachedThreadPool() 创建一个可根据需要创建新线程的线 ...

  2. Java多线程-新特性-线程池

    Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利.为了编写高效稳定可靠的多线程程序 ...

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

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

  4. Java并发编程:线程池的使用

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

  5. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  6. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

  7. JAVA基础拾遗-论线程池的线程粒度划分与深浅放置

    摘要:多线程任务处理对提高性能很有帮助,在Java中提供的线程池也方便了对多线程任务的实现.使用它很简单,而如果进行了不正确的使用,那么代码将陷入一团乱麻.因此如何正确地使用它,如以下分享,这个技能你 ...

  8. Java并发编程:线程池的使用(转)

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

  9. Java视频扩展知识 线程池的了解

     Java视频扩展知识   线程池的了解 1.简单介绍: Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的 ...

随机推荐

  1. nginx反向代理cas-server之2:生成证书,centOS下使用openssl生成CA证书(根证书、server证书、client证书)

    前些天搭好了cas系统,这几天一致再搞nginx和cas的反向代理,一直不成功,但是走http还是测试通过的,最终确定是ssl认证证书这一块的问题,原本我在cas服务端里的tomcat已经配置了证书, ...

  2. [附录]Discuz X2.5 模板目录结构注释说明

    /template/default/common  公共模板目录全局加载 block_forumtree.htm  DIY论坛树形列表模块 block_thread.htm  DIY帖子模块调用文件 ...

  3. JavaScript基础之注释,类型,输出,运算符

    JavaScript是一种依托于网页为宿主的脚本语言,JavaScript是一门非常强大的语言,尤其对于web端,用途广泛,好用,偏向于操作网页,可以操作网页中的任何一个元素,JavaScript的缺 ...

  4. Spring学习(18)--- AOP基本概念及特点

    AOP:Aspect Oriented Programing的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序程序功能的统一维护的一种技术 主要的功能是:日志记录,性能统计,安全控制, ...

  5. Hibernate入门(五)

    一 Hibernate继承映射 我们可以将继承层次结构类与数据库的表映射. 1. 每个层次类一张表 这个层次结构有三个类,Employee是Regular_Employee和Contract_Empl ...

  6. [0] 领域模型 VS 贫血模型

    贫血→结构体领域→封装方法的类 1.领域模型 也要能够 到达解耦,最好不要出现billdao.InsertBill(obj)这种2.领域方法 最好是自身的方法,如改变一个属性值,添加一个子集,而不是一 ...

  7. 关于MATLAB处理大数据坐标文件2017624

    经过一个下午找资料,已作出人工轨迹记录程序,这样就可以增加样本容量 接下来三个方向:特征.决策树.机械轨迹程序 虽然机械轨迹的程序相对好做,但是现有机械轨迹程序太过于死板,不能自行更改轨迹

  8. 基于Java SE的模拟双色球彩票系统

    1.双色球规则: ①双色球分为红球和蓝球,红球选择的范围为1-33,而且红球选择6个数字:蓝球选择的范围为1-16,而且只能选择1个数字. ②选择方式为随机选择号码和手动输入选择号码. ③生成号码的顺 ...

  9. Swift字符串可变性

    您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改: var variableString = "Horse" variableStrin ...

  10. 【LeetCode】67. Add Binary

    题目: Given two binary strings, return their sum (also a binary string). For example,a = "11" ...