线程池,顾名思义,放线程的池子嘛,这个池子可以存放多少线程取决于你自己采用什么样的线程池,你的硬件资源,以及并发线程的数量。JDK提供了下面的四种线程池:

固定线程数的线程池

  1. 最简单的

在Java中创建一个线程池,这很简单,只需要两行代码。

ExecutorService executor = Executor.newFixedTreadPool(6);//固定线程是6
//线程一般设置成processor核心数的倍数,因为我这台机器是6核的,所以设成6。这也是充分利用硬件嘛 //执行线程任务
executor.execute(new Runnable(){
@Override
public void run(){
//do nothing
}
}) executor.shutdown();

Executor是Java并发包中提供的,用来创造不同类型的线程池。

Attention

但是在多人合作或者是一些部署上线的项目里,是不允许去使用这种方法的,因为它是有性能隐患的。

Executors在创建线程池的时候,用的是new LinkedBlockingQueue(),它这个队列本身是无边界的,但是线程是固定数量的。这就意味着,在程序运行的过程中,最多会有N个线程在处于活动状态。每次有新的任务来就会等待,直到有线程处于空闲状态。所有的线程都会处于线程池里里面,直到shutdown()的执行。

它的问题就在于来者不拒,只要有任务来,你就进队列等着。在入队列和出队列用的并不是同一个lock,在多processor的机器上,是可以做到真正意义上的并行的。拿经典的生产者和消费者来举例子,在同一个时间点,有的在消费,有的在生产。

这种线程池不会销毁线程,不会拒绝任务,固定线程数。所以如果不停的加入任务,会导致很糟糕的内存占用,老年代可能会被占满。

  1. 稍复杂的(可以延时执行,也可以执行带返回值的任务)
public static void main(String[] args) throws InterruptedException, ExecutionException {
TestThread testThread = new TestThread();
System.out.println(testThread.processors); ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(6);
FutureTask<String> futureTask = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
});
scheduledExecutorService.submit(futureTask); //获取返回值
String result = futureTask.get();
System.out.println("result :"+result); //执行延时任务
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+": bomb!");
}
},3L,TimeUnit.SECONDS);
}

Output:

result :pool-1-thread-1

pool-1-thread-1: bomb!

缓存的线程池

核心池大小为0,线程池最大线程数目为最大整型,这意味着所有的任务一提交就会wait****。当线程池中的线程有60s没有执行任务就会被Kill,阻塞队列为SynchronousQueue。SynchronousQueue的take操作需要put操作等待,put操作需要take操作等待,否则会阻塞(线程池的阻塞队列不能存储,所以当目前线程处理忙碌状态时,会开辟新的线程来处理请求**),线程进入wait set。

总结一下这是一个可以无限扩大的线程池;适合处理执行时间比较小的任务;线程空闲时间超过60s就会被Kill,所以长时间处于空闲状态的时候,这种线程池几乎不占用资源,因为它压根没有线程在里面;阻塞队列没有存储空间,只要请求到来,就必须找到一条空闲线程去处理这个请求,找不到则在线程池新开辟一条线程。

如果主线程提交任务的速度远远大于CachedThreadPool的处理速度,则CachedThreadPool会不断地创建新线程来执行任务,这样有可能会导致系统耗尽CPU和内存资源,所以在使用该线程池时,要注意控制并发的任务数。如果是一个不断增长的任务需求,很容易就会到性能瓶颈,它会不停的创建新的线程。

 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
cachedThreadPool.shutdown();

Output:

pool-1-thread-2

pool-1-thread-6

pool-1-thread-1

pool-1-thread-7

pool-1-thread-8

pool-1-thread-3

pool-1-thread-5

pool-1-thread-9

pool-1-thread-4

pool-1-thread-10

单个线程的线程池

SingleThreadExecutor 是使用单个worker线程的Executor。只有一种情况会有新的线程加入线程池,那就是原有的线程运行时有抛出异常,这时就会有创建的新的线程来替代它的工作。

拿生产者消费者模型来说的话,这就是一个单一消费者的模型

(ps.一般可以用来做一些日志记录

 public static void main(String[] args) {
// 永远是一条线程
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int j = i;
singleThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + j);
}
});
}
singleThreadPool.shutdown(); }

Output:

pool-1-thread-1:0

pool-1-thread-1:1

pool-1-thread-1:2

pool-1-thread-1:3

pool-1-thread-1:4

pool-1-thread-1:5

pool-1-thread-1:6

pool-1-thread-1:7

pool-1-thread-1:8

pool-1-thread-1:9

Java提供的几种线程池的更多相关文章

  1. Java 1.ExecutorService四种线程池的例子与说明

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...

  2. JAVA基础知识|Executors提供的四种线程池

    一.Thread与Executors 开启新的线程,我们经常会采用如下方法: Thread thread =new Thread(new Runnable() { @Override public v ...

  3. javaSE中JDK提供的四种线程池

    对javaSE中JDK提供的四种线程池稍作整理   一.Executor   package java.util.concurrent; /** * @since 1.5 * @author Doug ...

  4. JDK提供的几种线程池比较

    JDK提供的几种线程池 newFixedThreadPool创建一个指定工作线程数量的线程池.每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中. ...

  5. java常用的几种线程池比较

    1. 为什么使用线程池 诸如 Web 服务器.数据库服务器.文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小的任务.请求以某种方式到达服务器,这种方式可能是通过网络协 ...

  6. Java 中的几种线程池,你之前用对了吗

    好久不发文章了,难道是因为忙,其实是因为懒.这是一篇关于线程池使用和基本原理的科普水文,如果你经常用到线程池,不知道你的用法标准不标准,是否有隐藏的 OOM 风险.不经常用线程池的同学,还有对几种线程 ...

  7. JDK提供的四种线程池代码详解

    一.线程池什么时候使用,会给我们带来什么好处? 如果很多用户去访问服务器,用户访问服务器的时间是非常短暂的,那么有可能在创建线程和销毁线程上花费的时间会远远大于访问所消耗的时间,如果采用线程池会使线程 ...

  8. Executors提供的四种线程池和自定义线程池

    JAVA并发编程——EXECUTORS 线程池的思想是一种对象池的思想,开放一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完毕,对象 ...

  9. Java 中的几种线程池这么用才是对的

    为什么要使用线程池 虽然大家应该都已经很清楚了,但还是说一下.其实归根结底最主要的一个原因就是为了提高性能. 线程池和数据库连接池是同样的道理,数据库连接池是为了减少连接建立和释放带来的性能开销.而线 ...

随机推荐

  1. c#基于Tablet pc实现的手写输入

    需要安装Tablet pc,win7的话 直接在控制面板>程序和应用>添加组建里面勾选上添加 然后就是下面的程序了,看代码 设计文件 namespace 手写识别 { partial cl ...

  2. 可视化流程设计——流程设计器演示(基于Silverlight)

    上一篇文章<通用流程设计>对鄙人写的通用流程做了一定的介绍,并奉上了相关源码.但一个好的流程设计必少不了流程设计器的支持,本文将针对<通用流程设计>中的流程的设计器做一个简单的 ...

  3. 关于客户端javascript的理解及事件浅析

    1,核心JavaScript和客服端JavaScript都有一个单线程执行模型.脚本和事件处理程序在同一时间只能执行一个,没有并发性.这样保持了js编程的简单性. 2,document的定义:一些呈现 ...

  4. 最近公共祖先(least common ancestors algorithm)

    lca问题是最近公共祖先问题,一般是针对树结构的.现在有两种方法来解决这样的问题 1. On-line algorithm 用比较长的时间做预处理.然后对每次询问进行回答. 思路:对于一棵树中的两个节 ...

  5. uva10883_Supermean_数学

    题目大意:给出n个数,每相邻两个数求平均数,得到n-1个数,再求平均数,得到n-2个数,......一直到最后一个数,输出这个数. 题目很简单,就是中间数据会比较大有点复杂,超过double的范围,而 ...

  6. C++程序设计1(侯捷video 1-6)

    一.头文件的防御式声明(video2) #ifndef __COMPLEX__ #define __COMPLEX__ //内容 #endif 二.初步感受模板(video2) 定义的时候: //复数 ...

  7. 【数据结构--二叉树】Java递归实现二叉树遍历

    参考链接:https://www.cnblogs.com/yaobolove/p/6213936.html 这有一棵树: 1.节点对象 package com.tree.mybinarytree; / ...

  8. Spring Boot2从入门到实战:统一异常处理

    都说管理的精髓就是“制度管人,流程管事”.而所谓流程,就是对一些日常工作环节.方式方法.次序等进行标准化.规范化.且不论精不精髓,在技术团队中,对一些通用场景,统一规范是必要的,只有步调一致,才能高效 ...

  9. PATB 1028. 人口普查(20)

    1028. 人口普查(20) 注意特判合理人数为0,否则格式错误.很暴力的sort排序找出最大最小. 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Stan ...

  10. leadcode的Hot100系列--617. 合并二叉树

    合并,就是两个树的结构交集部分,数据相加,否则,取非空部分. 所以,这里相当于是对两棵树同时遍历: 如果两棵树节点都不为空,则数据相加, 否则,直接指针把不为空的节点复制过来. 注:这里没有申请内存, ...