ExecutorService是java提供的用于管理线程池的类。

线程池的作用:

  - 控制线程数量

  - 重用线程

  当一个程序中创建了许多线程,并在任务结束后销毁,会给系统带来过度消耗资源,以及过度切换线程的危险,从而可能导致系统崩溃。为此我们应使用线程池来解决这个问题。

线程池的概念:

  首先创建一些线程,它们的集合称为线程池,当服务器受到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。

  在线程池编程模式下,任务是提交给整个线程池,而不是交给某个线程,线程池拿到任务就在内部找空闲的线程,再把任务交给内部的空闲线程,一个线程只能执行一个任务,但可以向线程池提交多个任务。

线程池的主要实现方法:

1、 Executors.newFixedThreadPool(int nThreads);

说明:创建固定大小(nThreads, 大小不能超过int的最大值)的线程池

// 线程数量  int nThreads = 20;

// 创建executor 服务  : ExecutorService executor = Executors.newFixedThreadPool(nThreads) ;

重载后的版本,需要传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors. newFixedThreadPool(nThreads, threadFactory);

 

说明:创建固定大小(nThreads, 大小不能超过int的最大值) 的线程池,缓冲任务的队列为LinkedBlockingQueue,大小为整型的最大数,当使用此线程池时,在同执行的任务数量超过传入的线程池大小值后,将会放入LinkedBlockingQueue,在LinkedBlockingQueue中的任务需要等待线程空闲后再执行,如果放入LinkedBlockingQueue中的任务超过整型的最大数时,抛出RejectedExecutionException。

2、Executors.newSingleThreadExecutor():创建大小为1的固定线程池。

ExecutorService executor = Executors.newSingleThreadExecutor();

重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors. newSingleThreadScheduledExecutor(ThreadFactory threadFactory)

说明:创建大小为1的固定线程池,执行任务的线程只有一个,其它的(任务)task都放在LinkedBlockingQueue中排队等待执行。

3、Executors.newCachedThreadPool();创建corePoolSize为0,最大线程数为整型的最大数,线程  keepAliveTime为1分钟,缓存任务的队列为SynchronousQueue的线程池。

ExecutorService executor = Executors.newCachedThreadPool();

当然也可以以下面的方式创建,重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors.newCachedThreadPool(ThreadFactory threadFactory) ;

说明:使用时,放入线程池的task任务会复用线程或启动新线程来执行,注意事项:启动的线程数如果超过整型最大值后会抛出RejectedExecutionException异常,启动后的线程存活时间为一分钟

4、Executors.newScheduledThreadPool(int corePoolSize):创建corePoolSize大小的线程池。

// 线程数量 int corePoolSize= 20;

// 创建executor 服务 : ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize) ;

重载后的版本,需要多传入实现了ThreadFactory接口的对象。

ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize, threadFactory) ;

说明:线程keepAliveTime为0,缓存任务的队列为DelayedWorkQueue,注意不要超过整型的最大值。

这种线程池有些不同,它可以实现定时器执行任务的功能,下面对第四种线程池进行代码演示:

  1. import java.util.concurrent.Executors;
  2. import java.util.concurrent.ExecutorService;
  3. import java.util.concurrent.ScheduledExecutorService;
  4. import java.util.concurrent.ScheduledFuture;
  5. import java.util.concurrent.TimeUnit;
  6.  
  7. class Temp extends Thread {
  8. public void run() {
  9. System.out.println("run");
  10. }
  11. }
  12.  
  13. public class ScheduledJob {
  14.  
  15. public static void main(String args[]) throws Exception {
  16.  
  17. Temp command = new Temp();
  18. ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
  19. //command代表执行的任务,5代表延迟5秒后开始执行,1代表每隔1秒执行一次,TimeUnit.SECONDS代表时间单位是秒
  20. ScheduledFuture<?> scheduleTask = scheduler.scheduleWithFixedDelay(command, 5, 1, TimeUnit.SECONDS);
  21.  
  22. }
  23. }

  下面以一段代码演示一般情况线程池的使用: 

  1. public static void main(String[] args) {
  2. ExecutorService threadpoo1 = Executors.newFixedThreadPool(2);
  3. for(int i=0;i<5;i++){
  4. Runnable runn=new Runnable() {
  5. public void run() {
  6. Thread t=Thread.currentThread();
  7. try {
  8. System.out.println(t+":正在运行");
  9. Thread.sleep(5000);
  10. System.out.println(t+"运行结束");
  11.        } catch (Exception e) {
  12.       System.out.println("线程被中断了");
  13.        }
  14.   }
  15. };
  16. threadpoo1.execute(runn);
  17. System.out.println("指派了一个任务交给线程池");
  18. threadpoo1.shutdown();
  19. System.out.println("停止线程池了!");
  20. }

自定义线程池

corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;

maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;

keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

unit:参数keepAliveTime的时间单位

workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:

ArrayBlockingQueue;

LinkedBlockingQueue;

SynchronousQueue;

threadFactory:线程工厂,主要用来创建线程;

handler:表示当拒绝处理任务时的策略,默认有以下四种取值:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。

ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。

ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)

ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

下面对自定义线程池进行代码演示:

MyTask实例类

  1. package com.bjsxt.height.concurrent018;
  2.  
  3. public class MyTask implements Runnable {
  4.  
  5. private int taskId;
  6. private String taskName;
  7.  
  8. public MyTask(int taskId, String taskName){
  9. this.taskId = taskId;
  10. this.taskName = taskName;
  11. }
  12.  
  13. public int getTaskId() {
  14. return taskId;
  15. }
  16.  
  17. public void setTaskId(int taskId) {
  18. this.taskId = taskId;
  19. }
  20.  
  21. public String getTaskName() {
  22. return taskName;
  23. }
  24.  
  25. public void setTaskName(String taskName) {
  26. this.taskName = taskName;
  27. }
  28.  
  29. @Override
  30. public void run() {
  31. try {
  32. System.out.println("run taskId =" + this.taskId);
  33. Thread.sleep(5*1000);
  34. //System.out.println("end taskId =" + this.taskId);
  35. } catch (InterruptedException e) {
  36. e.printStackTrace();
  37. }
  38. }
  39.  
  40. public String toString(){
  41. return Integer.toString(this.taskId);
  42. }
  43.  
  44. }
  1. package com.bjsxt.height.concurrent018;
  2.  
  3. import java.util.concurrent.ArrayBlockingQueue;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.LinkedBlockingQueue;
  7. import java.util.concurrent.ThreadPoolExecutor;
  8. import java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy;
  9. import java.util.concurrent.TimeUnit;
  10. import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
  11.  
  12. public class UseThreadPoolExecutor1 {
  13.  
  14. public static void main(String[] args) {
  15. /**
  16. * 在使用有界队列时,若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程,
  17. * 若大于corePoolSize,则会将任务加入队列,
  18. * 若队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的线程,
  19. * 若线程数大于maximumPoolSize,则执行拒绝策略。或其他自定义方式。
  20. *
  21. */
  22. ThreadPoolExecutor pool = new ThreadPoolExecutor(
  23. 1, //coreSize
  24. 2, //MaxSize
  25. 60, //
  26. TimeUnit.SECONDS,
  27. new ArrayBlockingQueue<Runnable>(3) //指定一种队列 (有界队列)
  28. //new LinkedBlockingQueue<Runnable>()
  29. , new MyRejected()
  30. //, new DiscardOldestPolicy()
  31. );
  32.  
  33. MyTask mt1 = new MyTask(1, "任务1");
  34. MyTask mt2 = new MyTask(2, "任务2");
  35. MyTask mt3 = new MyTask(3, "任务3");
  36. MyTask mt4 = new MyTask(4, "任务4");
  37. MyTask mt5 = new MyTask(5, "任务5");
  38. MyTask mt6 = new MyTask(6, "任务6");
  39.  
  40. pool.execute(mt1);
  41. pool.execute(mt2);
  42. pool.execute(mt3);
  43. pool.execute(mt4);
  44. pool.execute(mt5);
  45. pool.execute(mt6);
  46.  
  47. pool.shutdown();
  48.  
  49. }
  50. }

  1. package com.bjsxt.height.concurrent018;
  2.  
  3. import java.util.concurrent.ArrayBlockingQueue;
  4. import java.util.concurrent.BlockingQueue;
  5. import java.util.concurrent.ExecutorService;
  6. import java.util.concurrent.LinkedBlockingQueue;
  7. import java.util.concurrent.ThreadPoolExecutor;
  8. import java.util.concurrent.TimeUnit;
  9. import java.util.concurrent.atomic.AtomicInteger;
  10.  
  11. public class UseThreadPoolExecutor2 implements Runnable{
  12.  
  13. private static AtomicInteger count = new AtomicInteger(0);
  14.  
  15. @Override
  16. public void run() {
  17. try {
  18. int temp = count.incrementAndGet();
  19. System.out.println("任务" + temp);
  20. Thread.sleep(2000);
  21. } catch (InterruptedException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25.  
  26. public static void main(String[] args) throws Exception{
  27. //System.out.println(Runtime.getRuntime().availableProcessors());
  28. BlockingQueue<Runnable> queue =
  29. //new LinkedBlockingQueue<Runnable>();
  30. new ArrayBlockingQueue<Runnable>(10);
  31. ExecutorService executor = new ThreadPoolExecutor(
  32. 5, //core
  33. 10, //max
  34. 120L, //2fenzhong
  35. TimeUnit.SECONDS,
  36. queue);
  37.  
  38. for(int i = 0 ; i < 20; i++){
  39. executor.execute(new UseThreadPoolExecutor2());
  40. }
  41. Thread.sleep(1000);
  42. System.out.println("queue size:" + queue.size()); //
  43. Thread.sleep(2000);
  44. }
  45.  
  46. }

自定义拒绝策略演示

  1. package com.bjsxt.height.concurrent018;
  2.  
  3. import java.net.HttpURLConnection;
  4. import java.util.concurrent.RejectedExecutionHandler;
  5. import java.util.concurrent.ThreadPoolExecutor;
  6.  
  7. public class MyRejected implements RejectedExecutionHandler{
  8.  
  9. public MyRejected(){
  10. }
  11.  
  12. @Override
  13. public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
  14. System.out.println("自定义处理..");
  15. System.out.println("当前被拒绝任务为:" + r.toString());
  16.  
  17. }
  18.  
  19. }

使用ExecutorService实现线程池的更多相关文章

  1. Java 并发工具包——ExecutorService常用线程池

    1. 执行器服务 ExecutorService java.util.concurrent.ExecutorService 接口表示一个异步执行机制,使我们能够在后台执行任务.因此一个 Executo ...

  2. 转:java多线程CountDownLatch及线程池ThreadPoolExecutor/ExecutorService使用示例

    java多线程CountDownLatch及线程池ThreadPoolExecutor/ExecutorService使用示例 1.CountDownLatch:一个同步工具类,它允许一个或多个线程一 ...

  3. Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)

    多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...

  4. Android单例线程池

    package com.jredu.schooltong.manager; import java.util.concurrent.ExecutorService;import java.util.c ...

  5. Java并发——线程池Executor框架

    线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...

  6. java异步线程池同时请求多个接口数据

    一.主要使用类 . ExecutorService java线程池类 申明方式:ExecutorService exc = Executors.newFixedThreadPool(requestPa ...

  7. java线程池01-ThreadPoolExecutor构造方法参数的使用规则

    为了更好的使用多线程,JDK提供了线程池供开发人员使用,目的在于减少线程的创建和销毁次数,以此达到线程的重复利用. 其中ThreadPoolExecutor是线程池中最核心的一个类,我们先简单看一下这 ...

  8. Java多线程、线程池和线程安全整理

    多线程 1.1      多线程介绍 进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 1.2      Thread类 通 ...

  9. Java 基础 多线程和线程池基础

    一,多线程 1.1 多线程介绍 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负 ...

随机推荐

  1. 转载:EJB到底是什么

    这篇博客用通俗易懂的语言对EJB进行了介绍,写得很好,笔者在这里转载一下. 链接:https://www.cnblogs.com/strugglion/p/6027318.html

  2. 基于SpringBoot+SpringSecurity+mybatis+layui实现的一款权限系统

    这是一款适合初学者学习权限以及springBoot开发,mybatis综合操作的后台权限管理系统 其中设计到的数据查询有一对一,一对多,多对多,联合分步查询,充分利用mybatis的强大实现各种操作, ...

  3. Java四舍五入时保留指定小数位数

    方式一: double f = 3.1516; BigDecimal b = new BigDecimal(f); , BigDecimal.ROUND_HALF_UP).doubleValue(); ...

  4. CentOS7下PHP7.2安装redis扩展

    1.安装phpize(存在忽略) yum install php-devel 2.下载扩展源码包,直接用wget,一般放在 /usr/local/src wget https://github.com ...

  5. js根据年份获取某月份有几天

    function getNum(year, month) { var temp; month = parseInt(month, 10); temp = new Date(year, month, 0 ...

  6. vue 路由对象(常用的)

    路由对象 在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新. 路由对象暴露了以下属性: $route.path ...

  7. JavaSE库存管理系统项目实战

    需求分析 企业库房用于存放成品.半成品.原材料.工具等物资,一般情况下,这些物资统称为物料.库存管理常见业务包括物资的入库.出库.盘点.退货.报废以及财务核算等,业务逻辑比较复杂,库房信息系统项目开发 ...

  8. Python正则表达式-基础

    Python正则表达式-基础 本文转载自昔日暖阳,原文地址:http://www.osheep.cn/4806.html python使用正则,需要先引入re模块 import re 匹配符 单个字符 ...

  9. Vue简单使用,

    一些零碎的知识点: 在js中变量的声明 有三种方式: let,var, const let: 对应的是一个块级作用域 { let a = 12 } console.log(a) 这是未声明的, var ...

  10. CMDB介绍

    CMDB https://lupython.gitee.io/2018/05/05/CMDB%E4%BB%8B%E7%BB%8D/ 尚泽凯博客地址 传统运维与自动化运维的区别 传统运维: ​ 1.项目 ...