一、概述:

为什么要使用线程池?在实际开发过程中,如果不使用线程池,有可能会不加节制的去创建新的线程导致服务器cpu资源占满,无法相应其他请求。所以使用线程池就是为了控制开启多线程情况下,对其有开销控制,不会导致上面问题发生。在创建线程池时,我们建议使用ThreadPoolExecutor 而代替Executors 去创建是因为Executors内部也是使用的ThreadPoolExecutor进行的创建,并且有一定的局限性。所以为了创建符合自己的业务场景需要我们使用ThreadPoolExecutor进行创建线程池。

ThreadPoolExecutor的构造函数:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

corePoolSize:线程池中的可并行运行线程数量,当前启用线程数等于该值后待开启线程将会将待开启的线程放入到等待队列中去;

maximumPoolSize: 直接提交队列时最多线程数量,

keepAliveTime:当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内被销毁;

unit:keepAliveTime的单位

workQueue:任务队列,被添加到线程池中,但尚未被执行的任务;它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列几种;

threadFactory:线程工厂,用于创建线程,一般用默认即可;

handler:拒绝策略;当任务太多来不及处理时,如何拒绝任务;

二、四种不同任务队列

线程池中的不同任务队列有着不同的线程任务处理规则。

1 , 直接提交队列 (SynchronousQueue实现)

规则最简单的任务队列,主要使用SynchronousQueue进行存放线程实现类。其中第一个corePoolSize值设置无效,默认设置为0,主要设置其maximumPoolSize。当我们在同时开启多个线程时,在maximumPoolSize之内的都可以被正常开启,当超过maximumPoolSize数量时则执行拒绝策略。

package com.xiaohui.thread;import java.util.concurrent.*;/*** SynchronousQueue 直接提交队列* corePoolSize 无用,超过maximumPoolSize 则执行拒绝策略*/
public class SynchronousQueueThreadPool {private static ExecutorService pool;public static void main( String[] args ){pool = new ThreadPoolExecutor(0, 4, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for(int i=0;i<5;i++) {pool.execute(new ThreadTask());}}
}
package com.xiaohui.thread;import java.util.Date;public class ThreadTask implements Runnable{public ThreadTask() {}public void run() {System.out.println(Thread.currentThread().getName()+"----start sleep"+new Date().toLocaleString());long l = System.currentTimeMillis();try{Thread.sleep(2000);System.out.println(Thread.currentThread().getName()+"----sleep   end"+new Date().toLocaleString()+",运行时间:"+(System.currentTimeMillis()-l));}catch (Exception e){}}
}

打印结果:48秒时同时开启四条线程,开启第五条时,直接执行拒绝测试抛出RejectedExecutionException

D:\Java\jdk1.8.0_131\bin\java.exe "-javaagent:D:\Java\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=55468:D:\Java\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\Java\jdk1.8.0_131\jre\lib\charsets.jar;D:\Java\jdk1.8.0_131\jre\lib\deploy.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;D:\Java\jdk1.8.0_131\jre\lib\javaws.jar;D:\Java\jdk1.8.0_131\jre\lib\jce.jar;D:\Java\jdk1.8.0_131\jre\lib\jfr.jar;D:\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;D:\Java\jdk1.8.0_131\jre\lib\jsse.jar;D:\Java\jdk1.8.0_131\jre\lib\management-agent.jar;D:\Java\jdk1.8.0_131\jre\lib\plugin.jar;D:\Java\jdk1.8.0_131\jre\lib\resources.jar;D:\Java\jdk1.8.0_131\jre\lib\rt.jar;F:\stuproject\ThreadPool\target\classes com.xiaohui.thread.SynchronousQueueThreadPool
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.xiaohui.thread.ThreadTask@330bedb4 rejected from java.util.concurrent.ThreadPoolExecutor@2503dbd3[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)at com.xiaohui.thread.SynchronousQueueThreadPool.main(SynchronousQueueThreadPool.java:15)
pool-1-thread-1----start sleep2020-7-22 17:58:48
pool-1-thread-2----start sleep2020-7-22 17:58:48
pool-1-thread-3----start sleep2020-7-22 17:58:48
pool-1-thread-4----start sleep2020-7-22 17:58:48
pool-1-thread-1----sleep   end2020-7-22 17:58:50,运行时间:2000
pool-1-thread-3----sleep   end2020-7-22 17:58:50,运行时间:2001
pool-1-thread-2----sleep   end2020-7-22 17:58:50,运行时间:2000
pool-1-thread-4----sleep   end2020-7-22 17:58:50,运行时间:2001Process finished with exit code 1

2 , 有界任务队列(ArrayBlockingQueue实现)

在有界任务队列中创建线程时,当创建数量达到corePoolSize时,其他需要创建的队列会放到等待队列中,当等待队列中达到初始化的大小后,继续创建,当超过maximumPoolSize 时会执行拒绝策略(当同时启用的任务较少时,超过max数量也正常执行,不是按上述进行。当启用数量较大时则按上面进行执行)

package com.xiaohui.thread;import java.util.concurrent.*;public class ArrayBlockingQueueThreadPool {private static ExecutorService pool;public static void main( String[] args ){pool = new ThreadPoolExecutor(4, 8, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(6), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for(int i=0;i<10;i++) {pool.execute(new ThreadTask());}}
}

ThreadTask类同1中的代码。打印如下(当同时开启数量为15时会抛出拒绝策略错误):

pool-1-thread-4----start sleep2020-7-22 18:32:03
pool-1-thread-2----start sleep2020-7-22 18:32:03
pool-1-thread-3----start sleep2020-7-22 18:32:03
pool-1-thread-1----start sleep2020-7-22 18:32:03
pool-1-thread-4----sleep   end2020-7-22 18:32:05,运行时间:2000
pool-1-thread-4----start sleep2020-7-22 18:32:05
pool-1-thread-1----sleep   end2020-7-22 18:32:05,运行时间:2000
pool-1-thread-1----start sleep2020-7-22 18:32:05
pool-1-thread-2----sleep   end2020-7-22 18:32:05,运行时间:2023
pool-1-thread-2----start sleep2020-7-22 18:32:05
pool-1-thread-3----sleep   end2020-7-22 18:32:05,运行时间:2023
pool-1-thread-3----start sleep2020-7-22 18:32:05
pool-1-thread-4----sleep   end2020-7-22 18:32:07,运行时间:2000
pool-1-thread-4----start sleep2020-7-22 18:32:07
pool-1-thread-1----sleep   end2020-7-22 18:32:07,运行时间:2002
pool-1-thread-1----start sleep2020-7-22 18:32:07
pool-1-thread-2----sleep   end2020-7-22 18:32:07,运行时间:2000
pool-1-thread-3----sleep   end2020-7-22 18:32:07,运行时间:2002
pool-1-thread-4----sleep   end2020-7-22 18:32:09,运行时间:2000
pool-1-thread-1----sleep   end2020-7-22 18:32:09,运行时间:2000

3,无界任务队列(LinkedBlockingQueue实现)

在无界任务队列中 最大线程数量参数无效,同时可运行线程数量为corePoolSize,当开启的线程数量超过corePoolSize时,待开启的线程会放入链表队列中。没有最大线程数量限制。当线程池中的线程执行完成之后,将从链表等待队列中获取进行执行。

package com.xiaohui.thread;import java.util.concurrent.*;public class LinkedBlockingQueueThreadPool {private static ExecutorService pool;public static void main( String[] args ){pool = new ThreadPoolExecutor(3,6, //无效参数1000,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for(int i=0;i<10;i++) {pool.execute(new ThreadTask());}}
}

ThreadTask类同1中的代码。打印如下(同时开启三个,三个线程同时结束后,在开启三个进行执行...):

pool-1-thread-1----start sleep2020-7-22 18:34:51
pool-1-thread-3----start sleep2020-7-22 18:34:51
pool-1-thread-2----start sleep2020-7-22 18:34:51
pool-1-thread-1----sleep   end2020-7-22 18:34:53,运行时间:2000
pool-1-thread-1----start sleep2020-7-22 18:34:53
pool-1-thread-3----sleep   end2020-7-22 18:34:53,运行时间:2000
pool-1-thread-2----sleep   end2020-7-22 18:34:53,运行时间:2000
pool-1-thread-3----start sleep2020-7-22 18:34:53
pool-1-thread-2----start sleep2020-7-22 18:34:53
pool-1-thread-2----sleep   end2020-7-22 18:34:55,运行时间:2013
pool-1-thread-2----start sleep2020-7-22 18:34:55
pool-1-thread-3----sleep   end2020-7-22 18:34:55,运行时间:2022
pool-1-thread-3----start sleep2020-7-22 18:34:55
pool-1-thread-1----sleep   end2020-7-22 18:34:55,运行时间:2024
pool-1-thread-1----start sleep2020-7-22 18:34:55
pool-1-thread-2----sleep   end2020-7-22 18:34:57,运行时间:2001
pool-1-thread-2----start sleep2020-7-22 18:34:57
pool-1-thread-3----sleep   end2020-7-22 18:34:57,运行时间:2000
pool-1-thread-1----sleep   end2020-7-22 18:34:57,运行时间:2001
pool-1-thread-2----sleep   end2020-7-22 18:34:59,运行时间:2000

4,优先任务队列(PriorityBlockingQueue实现)

优先任务队列中,线程类需要实现Comparable接口。在首次启动线程后,同时开启了corePoolSize个线程之后,其他需要待执行的线程队列将被放到PriorityBlockingQueue队列中,并进行了比较排序,首次启用的线程执行完成之后,将会从待执行队列中获取排序后的corePoolSize个线程,并进行执行。

package com.xiaohui.thread;import java.util.Date;public class ThreadTask implements Runnable,Comparable<ThreadTask>{private int weight = 0;public ThreadTask() {}public ThreadTask(int weight) {this.weight = weight;}public void run() {System.out.println(weight+"--"+Thread.currentThread().getName()+"----start sleep"+new Date().toLocaleString());long l = System.currentTimeMillis();try{Thread.sleep(2000);
//            System.out.println(weight+"--"+Thread.currentThread().getName()+"----sleep   end"+new Date().toLocaleString()+",运行时间:"+(System.currentTimeMillis()-l));}catch (Exception e){}}public int compareTo(ThreadTask o) {return this.weight > o.weight  ?-1:1;}
}
package com.xiaohui.thread;import java.util.concurrent.*;public class PriorityBlockingQueueThreadPool {private static ExecutorService pool;public static void main( String[] args ){pool = new ThreadPoolExecutor(4,10, //无效参数1000,TimeUnit.MILLISECONDS,new PriorityBlockingQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for(int i=0;i<10;i++) {pool.execute(new ThreadTask(i));}}
}

运行打印结果如下(首次四个线程2、1、3、0为无序的执行,当前4个执行完成之后,进行按排序后的线程获取执行):

2--pool-1-thread-3----start sleep2020-7-22 18:44:33
1--pool-1-thread-2----start sleep2020-7-22 18:44:33
3--pool-1-thread-4----start sleep2020-7-22 18:44:33
0--pool-1-thread-1----start sleep2020-7-22 18:44:33
9--pool-1-thread-3----start sleep2020-7-22 18:44:35
8--pool-1-thread-2----start sleep2020-7-22 18:44:35
7--pool-1-thread-4----start sleep2020-7-22 18:44:35
6--pool-1-thread-1----start sleep2020-7-22 18:44:35
5--pool-1-thread-3----start sleep2020-7-22 18:44:37
4--pool-1-thread-2----start sleep2020-7-22 18:44:37

Java 线程池的简单使用及介绍相关推荐

  1. JAVA线程池的简单实现及优先级设置

    我们大家都知道,在处理多线程服务并发时,由于创建线程需要占用很多的系统资源,所以为了避免这些不必要的损耗,通常我们采用线程池来解决这些问题.   线程池的基本原理是,首先创建并保持一定数量的线程,当需 ...

  2. java线程池的简单使用

    线程池是预先创建的一种技术,线程池在还没有任务到来之前,创建一定数量的线程,放入空闲队列中,然后对这些资源进行复用,减少频繁的创建和销毁对象. JDK 1.5 版本以上提供了现成的线程池. java里 ...

  3. JAVA线程池原理以及几种线程池类型介绍

    在什么情况下使用线程池? 1.单个任务处理的时间比较短      2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销      2.如不使用线程池, ...

  4. java线程池有什么作用_java线程池的作用是什么?线程池介绍

    你知道java中线程池的作用是什么吗?那么究竟什么是线程池呢?都有哪些类型呢?让我们对以上的问题来进行详细的了解吧. 一.java线程池作用 第一个我们先来对它的作用进行一下简单的介绍,使用线程池的优 ...

  5. java 任务池_多线程的应用-异步任务线程池的简单实现

    对于服务端的应用而言,经常会出现比如定时任务,或者任务的异步执行,熟悉Java开发的开发者,经常会使用Executors类,其提供了4种不同的线程池: ​newCachedThreadPool, ne ...

  6. java线程池概念_Java 线程池概念、原理、简单实现

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

  7. Java线程池使用与原理

    线程池是什么? 我们可以利用java很容易创建一个新线程,同时操作系统创建一个线程也是一笔不小的开销.所以基于线程的复用,就提出了线程池的概念,我们使用线程池创建出若干个线程,执行完一个任务后,该线程 ...

  8. Java线程池实现原理及其在美团业务中的实践

    来自:美团技术团队 随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流.使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器.J.U.C提供的线程池ThreadPoolExecuto ...

  9. JAVA线程池(ThreadPoolExecutor)源码分析

    JAVA5提供了多种类型的线程池,如果你对这些线程池的特点以及类型不太熟悉或者非常熟悉,请帮忙看看这篇文章(顺便帮忙解决里面存在的问题,谢谢!):     http://xtu-xiaoxin.ite ...

最新文章

  1. javascript中数据类型转换
  2. 越来越多BCH全节点客户端对BCH意味着什么?
  3. RabbitMQ 3.6 安装
  4. C++ Primer 5th笔记(chap 14 重载运算和类型转换)下标运算符[]
  5. Django的分页器(paginator)
  6. VMware 虚拟上网的的三种模式 ——bridged、host-only、NAT 模式
  7. Qt下libusb-win32的使用(一)打印设备描述符
  8. 股价狂涨 500 亿,小米手机业务与造车可否兼得?
  9. Django相关配置(包括数据库、templates、static等)信息—Django2.0
  10. Firefox4开发计划公布:使浏览器得更快更强
  11. PoJ3278--Catch That Cow(Bfs)
  12. 一个基于SpringBoot的在线教育系统「源码开源」
  13. Java编程之从零开始学Java——初始java
  14. 先测试再开发?TDD测试驱动开发了解一下?
  15. 关于汽油动力汽车和混合动力汽车的环保问题。
  16. PostgreSQL 设置远程访问
  17. 【概率论与数理统计】python实验
  18. 一次买房子血淋淋的教训
  19. Glide控制显示图片上方2个圆角(或4个都是圆角)
  20. 浙工大c语言期中考试试题答案,浙工大c语言程序设计期末试卷2

热门文章

  1. Hive安装Version2.1.0
  2. 【转载】Apache Ranger剖析:Hadoop生态圈的安全管家
  3. pulsar 卸载数据到aws-s3
  4. mysql 查看数据库字段是否存在,mysql查询某张表是否存在某个字段和判断是否存在某个表名...
  5. vue 组件 props配置
  6. JDK的下载、安装和配置
  7. mysql配置master_mysql 主从配置(master/slave)
  8. Netty学习笔记(六) 简单的聊天室功能之WebSocket客户端开发实例
  9. 防止误删的神器-ECS实例删除保护
  10. 1094:零起点学算法01——第一个程序Hello World!