搞懂Java线程池

身为程序员我们对线程是再熟悉不过了,多线程并发算是Java进阶的知识,用好多线程不容易有太多的坑。创建线程也算是一个"重"操作。创建线程的语句是new Thread()咋一看好像就是new了一个对象。

没错是new了个对象,但是不仅仅是普通对象那样在堆中分配了一块内存,它还需要调用操作系统内核API,然后操作系统再为线程分配一些资源。所以较普通对象,线程就比较“重了”。所以我们要避免频繁的创建和销毁线程,还得控制一下线程的数量。线程池就是用来完成这一项使命的。

所以多线程就离不开线程池,所以要掌握多线程编程,线程池的了解必不可少。

线程池的设计就是采用生产者-消费者模式,线程池里面的线程是消费者,我们塞给线程池的任务是生产者。可以理解成线程池就是火车站售票厅,线程池里面的线程就是火车站售票厅窗口员工,我们去买票或者退票改签就是给窗口员工任务也就是生产,然后窗口员工帮我们办理业务,也就是消费。

一般我们是用ThreadPoolExecutor来创建线程池,我找了里面参数最多的构造器。

1、corePoolSize

按字面翻译过来就是核心池大小,其实就是线程池保有的最小的线程数,这里需要注意一下,初始化线程池的时候,除非调用prestartAllCoreThreads或者prestartCoreThread这两个方法,这两个方法分别是在无任务到来之前预创建所有核心线程或者创建一个线程。否则线程池初始化后没任务进来前是没有线程的。只有当任务来了才会创建线程。

所以这里保有的核心数指的是,当线程池创建了这么多的线程之后,会保留的不会被回收的线程数,超过corePoolSize的线程在一定时间之后就会被回收。

但是java1.6新增了一个allowCoreThreadTimeOut(boolean value)方法,当设为true时候,所有的线程都会超时回收,包括核心线程。

2、maximumPoolSize

最大线程数,也就是池里面能有的最大的线程数量。也就是火车站售票厅窗口所有的窗口都有员工在服务。特别是在节假日的时候,基本上窗口都会开放。

3、keepAliveTime、TimeUnit

keepAliveTime就是存活时间,TimeUnit是时间单位,来表明keepAliveTime的数字是秒啊还是毫秒啊等等。

这两个参数就是当我们线程池存在的线程数量超过corePoolSize时,如果有个线程已经空闲了keepAliveTime这么长的时间,那么这个空闲线程就要被回收了,就类似于出行高峰期过去了,售票厅窗口可以关闭几个了。总不能都没人了还开这么多窗口把,浪费呀。

4、workQueue

工作队列,是阻塞队列。队列存储的也就是线程需要执行的Runnable,也就是任务。对应着就是去售票厅排队的我们。

5、threadFactory

按名字翻译过来就是线程工厂了,也就是我们可以搞个工厂,然后自定义如何创建线程,比如给线程set下名字啊等。然后线程池就会按照工厂定义的方式创建线程。就是如果不设定线程的名字的话,线程名可能就是什么thread-1这样的,对于我们排查问题不太方便,所以给个名字来标识一下比较好。

6、handler

这个是拒绝策略,也就是当线程池中所有的线程都在执行任务,并且工作队列(是有界队列)也排满了,那再有任务提交就会执行拒绝策略。ThreadPoolExecutor提供了四种拒绝策略

1、ThreadPoolExecutor.AbortPolicy()
是默认的拒绝策略,会抛出 RejectedExcecutionException。
2、ThreadPoolExecutor.CallerRunsPolicy()
让提交任务的线程自己去执行这个任务。。好像这样做挺有道理的..我没空你自己搞去
3、ThreadPoolExecutor.DiscardOldestPolicy()
丢弃最老的任务,也就是工作队列里最前面的任务,丢弃了之后把新任务加入到工作队列中...真的不公平啊
4、ThreadPoolExecutor.DiscardPolicy()
直接丢弃任务,并且不抛出任何异常...假装没看到系列

除了这四种还可以自定义拒绝策略,建议自定义拒绝策略。因为更加的友好,可以设置成服务降级啊等操作。

注意

Java并发包还提供了Executors,可以快速创建线程池,但是不推荐使用Executors。因为Executors创建线程池都是默认使用无界队列LinkedBlockingQueue,在高负载的情况下容易OOM。所以建议使用有界队列。

总结

所以线程池就是生产者-消费者模型的实现,线程池约束了线程的数量,也避免频繁的创建和销毁线程。工作队列得存在使得任务有序的进行,完美!

以上所述是小编给大家介绍的Java线程池详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • java中通用的线程池实例代码

    复制代码 代码如下: package com.smart.frame.task.autoTask; import java.util.Collection;import java.util.Vector; /** * 任务分发器 */public class TaskManage extends Thread{    protected Vector<Runnable> tasks = new Vector<Runnable>();    protected boolean run

  • 支持生产阻塞的Java线程池

    通常来说,生产任务的速度要大于消费的速度.一个细节问题是,队列长度,以及如何匹配生产和消费的速度. 一个典型的生产者-消费者模型如下:   在并发环境下利用J.U.C提供的Queue实现可以很方便地保证生产和消费过程中的线程安全.这里需要注意的是,Queue必须设置初始容量,防止生产者生产过快导致队列长度暴涨,最终触发OutOfMemory. 对于一般的生产快于消费的情况.当队列已满时,我们并不希望有任何任务被忽略或得不到执行,此时生产者可以等待片刻再提交任务,更好的做法是,把生产者阻塞在提交任

  • Java 线程池详解及实例代码

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收. 所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因. 例如Android中常见到的很多通用组件一般都离不开"池"的概念,如各种图片

  • 详谈Java几种线程池类型介绍及使用方法

    一.线程池使用场景 •单个任务处理时间短 •将需处理的任务数量大 二.使用Java线程池好处 1.使用new Thread()创建线程的弊端: •每次通过new Thread()创建对象性能不佳. •线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom. •缺乏更多功能,如定时执行.定期执行.线程中断. 2.使用Java线程池的好处: •重用存在的线程,减少对象创建.消亡的开销,提升性能. •可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞

  • 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } } ).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限

  • 深入java线程池的使用详解

    在Java 5.0之前启动一个任务是通过调用Thread类的start()方法来实现的,任务的提于交和执行是同时进行的,如果你想对任务的执行进行调度或是控制 同时执行的线程数量就需要额外编写代码来完成.5.0里提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接 池的线程池来执行任务.这个架构主要有三个接口和其相应的具体类组成.这三个接口是Executor, ExecutorService.ScheduledExecutorService,让我们先用一个图

  • Java 线程池ExecutorService详解及实例代码

    Java 线程池ExecutorService 1.线程池 1.1什么情况下使用线程池 单个任务处理的时间比较短. 将需处理的任务的数量大. 1.2使用线程池的好处 减少在创建和销毁线程上所花的时间以及系统资源的开销. 如果不使用线程池,有可能造成系统创建大量线程而导致消耗系统内存以及"过度切换"; 2.ExecutorService和Executors 2.1简介 ExecutorService是一个接口,继承了Executor, public interface ExecutorS

  • Java Socket编程实例(三)- TCP服务端线程池

    一.服务端回传服务类: import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.logging.Level; import java.util.logging.Logger; public class EchoProtocol implements Runnable { private static f

  • java线程池:获取运行线程数并控制线程启动速度的方法

    在java里, 我们可以使用Executors.newFixedThreadPool 来创建线程池, 然后就可以不停的创建新任务,并用线程池来执行了. 在提交任务时,如果线程池已经被占满,任务会进到一个队列里等待执行. 这种机制在一些特定情况下会有些问题.今天我就遇到一种情况:创建线程比线程执行的速度要快的多,而且单个线程占用的内存又多,所以很快内存就爆了. 想了一个办法,就是在提交任务之前,先检查目前正在执行的线程数目,只有没把线程池占满的时候在去提交任务. 代码很简单: int thread

  • 一篇文章带你搞懂Java线程池实现原理

    目录 1. 为什么要使用线程池 2. 线程池的使用 3. 线程池核心参数 4. 线程池工作原理 5. 线程池源码剖析 5.1 线程池的属性 5.2 线程池状态 5.3 execute源码 5.4 worker源码 5.5 runWorker源码 1. 为什么要使用线程池 使用线程池通常由以下两个原因: 频繁创建销毁线程需要消耗系统资源,使用线程池可以复用线程. 使用线程池可以更容易管理线程,线程池可以动态管理线程个数.具有阻塞队列.定时周期执行任务.环境隔离等. 2. 线程池的使用 /** *

  • 搞懂Java线程池

    身为程序员我们对线程是再熟悉不过了,多线程并发算是Java进阶的知识,用好多线程不容易有太多的坑.创建线程也算是一个"重"操作.创建线程的语句是new Thread()咋一看好像就是new了一个对象. 没错是new了个对象,但是不仅仅是普通对象那样在堆中分配了一块内存,它还需要调用操作系统内核API,然后操作系统再为线程分配一些资源.所以较普通对象,线程就比较"重了".所以我们要避免频繁的创建和销毁线程,还得控制一下线程的数量.线程池就是用来完成这一项使命的. 所以

  • 一篇文章彻底搞懂jdk8线程池

    这可能是最简短的线程池分析文章了. 顶层设计,定义执行接口 Interface Executor(){ void execute(Runnable command); } ExecutorService,定义控制接口 interface ExecutorService extends Executor{ } 抽象实现ExecutorService中的大部分方法 abstract class AbstractExecutorService implements ExecutorService{ /

  • 一文彻底搞懂java多线程和线程池

    目录 什么是线程 一. Java实现线程的三种方式 1.1.继承Thread类 1.2.实现Runnable接口,并覆写run方法 二. Callable接口 2.1 Callable接口 2.2 Future接口 2.3 Future实现类是FutureTask. 三. Java线程池 3.1.背景 3.2.作用 3.3.应用范围 四. Java 线程池框架Executor 4.1.类图: 4.2 核心类ThreadPoolExecutor: 4.3 ThreadPoolExecutor逻辑结

  • 一文搞懂Java创建线程的五种方法

    目录 题目描述 解题思路 代码详解 第一种 继承Thread类创建线程 第二种:实现Runnable接口创建线程 第三种:实现Callable接口,通过FutureTask包装器来创建Thread线程 第四种:使用ExecutorService.Callable(或者Runnable).Future实现返回结果的线程 第五种:使用ComletetableFuture类创建异步线程,且是据有返回结果的线程 题目描述 Java创建线程的几种方式 Java使用Thread类代表线程,所有线程对象都必须

  • 一文搞懂Java中对象池的实现

    目录 1. 什么是对象池 2. 为什么需要对象池 3. 对象池的实现 4. 开源的对象池工具 5. JedisPool 对象池实现分析 6. 对象池总结 最近在分析一个应用中的某个接口的耗时情况时,发现一个看起来极其普通的对象创建操作,竟然每次需要消耗 8ms 左右时间,分析后发现这个对象可以通过对象池模式进行优化,优化后此步耗时仅有 0.01ms,这篇文章介绍对象池相关知识. 1. 什么是对象池 池化并不是什么新鲜的技术,它更像一种软件设计模式,主要功能是缓存一组已经初始化的对象,以供随时可以

  • Java线程池配置的一些常见误区总结

    前言 由于线程的创建和销毁对操作系统来说都是比较重量级的操作,所以线程的池化在各种语言内都有实践,当然在 Java 语言中线程池是也非常重要的一部分,有 Doug Lea 大神对线程池的封装,我们使用的时候是非常方便,但也可能会因为不了解其具体实现,对线程池的配置参数存在误解. 我们经常在一些技术书籍或博客上看到,向线程池提交任务时,线程池的执行逻辑如下: 当一个任务被提交后,线程池首先检查正在运行的线程数是否达到核心线程数,如果未达到则创建一个线程. 如果线程池内正在运行的线程数已经达到了核心

  • Java线程池实现原理总结

    目录 一.线程池参数 二.线程池执行流程 三.四种现成的线程池 要理解实现原理,必须把线程池的几个参数彻底搞懂,不要死记硬背 一.线程池参数 1.corePoolSize(必填):核心线程数. 2.maximumPoolSize(必填):最大线程数. 3.keepAliveTime(必填):线程空闲时长.如果超过该时长,非核心线程就会被回收. 4.unit(必填):指定keepAliveTime的时间单位.常用的有:TimeUnit.MILLISECONDS(毫秒).TimeUnit.SECON

  • 一文搞懂Java ScheduledExecutorService的使用

    目录 一.创建ScheduledExecutorService对象 二.ScheduledExecutorService方法 三.固定速率和固定延时的区别 1. 固定速率 2. 固定延时 四.调度多个任务 五.其他要点 JUC包(java.util.concurrent)中提供了对定时任务的支持,即ScheduledExecutorService接口. 本文对ScheduledExecutorService的介绍,将基于Timer类使用介绍进行,因此请先阅读Timer类使用介绍文章. 此处为语雀

  • JAVA线程池专题(概念和作用)

    线程池的作用 我们在用一个东西的时候,首先得搞明白一个问题.这玩意是干嘛的,为啥要用这个,用别的不行吗.那么一个一个解决这些问题 我们之前都用过数据库连接池,线程池的作用和连接池有点类似,频繁的创建,销毁线程会造成大量的不必要的性能开销,所以这个时候就出现了一个东西统一的管理线程,去负责线程啥时候销毁,啥时候创建,以及维持线程的状态,当程序需要使用线程的时候,直接从线程池拿,当程序用完了之后,直接把线程放回线程池,不需要去管线程的生命周期,专心的执行业务代码就行. 当然,如果非要是自己想手动ne

随机推荐