`
wbj0110
  • 浏览: 1602206 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

java线程池原理

    博客分类:
  • Java
阅读更多

 

下面开始今天的正文,线程池的核心类为ThreadPoolExecutor类,线程池基本是围绕它展开的,网上有大堆的学习资料,想快速入门,还是看JDK API,里面有详细的类说明,这里主要介绍其流程以及分析固定线程池(Executors.newFixedThreadPool)和缓存线程池(Executors.newCachedThreadPool)的原理

开始之前,先介绍一下核心线程和最大线程大小的概念:

  核心线程大小(corePoolSize):线程池中存在的线程数,包括空闲线程(就是还在存活时间内,没有干活,等着任务的线程)

  最大池大小(maximumPoolSize):线程池允许存在的最大线程数

ThreadPoolExecutor 将根据 corePoolSize 和 maximumPoolSize 设置的边界自动调整池大小,如果设置的 corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池;如果将 maximumPoolSize 设置为基本的无界值(如Integer.MAX_VALUE),则允许池适应任意数量的并发任务。在大多数情况下,核心和最大池大小仅通过构造函数来设置,不过也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 进行动态更改。

 

当新任务在方法 execute(java.lang.Runnable) 中提交时,遵循以下几条规则:

规则1.如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队,即使其他辅助线程是空闲的。

规则2.如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则首选将任务添加到等待队列,而不添加新的线程。

规则3.如果无法将请求加入队列(队列满),则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝,

 

固定线程池(Executors.newFixedThreadPool)原理

固定线程池是怎么实现线程池固定的呢?看看他的构造函数

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

他的工作线程是固定的,而且最大线程跟核心线程数是一样的,这里就保证了线程数不会超过设定的数值,那他怎么保证任务不被reject掉呢,重点在与他的任务队列,是new LinkedBlockingQueue<Runnable>(),这是一个无界的线程安全队列,是什么意思呢,它可以存放无限个(准确说不是无限的,有个默认值Integer.MAX_VALUE的容量)任务,对照上面的规则2,只有任务队列满时才创建新线程,所以...,你懂的,这也从另外一面保障了线程数不超过设定值

再来看看缓存线程池(Executors.newCachedThreadPool),构造函数

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

神马,他的核心线程是0,初看,确定让人"大吃一斤",问题一,核心线程都没有,怎么工作?先来看看jdk api上对它的介绍:

创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。

重点词汇,以前的线程可用时将重用它们,问题二,怎么重用?如果没有可用线程,则创建一个,并移除超过60s未被使用的线程,问题三,怎么保证60s移除未被使用的线程。这两个问题搞清除了,带缓存功能的线程池你就搞清楚了

首先看问题一:

既然核心线程为0,那么运行线程肯定>=核心线程了,所以规则一不适用;规则二的应用就要要情况了,(1)第一个任务是肯定进不了队列的,因为缓存线程池的队列是SynchronousQueue,这个很有意思(不懂的去最开始的链接大致看一下),因为他的内部没有任何容量,只有当你正好同时使用一对操作(插入-移除)时,元素才存在,简单地说就是,当你进行offer操作时,如果正好有另外一个线程在执行插入操作时,那么恭喜你中奖了,可以拿到元素,其他时候,你都是拿不到的。所以对于第一个任务,规则2是不适用的,这时就规则3起作用了,调用addIfUnderMaximumPoolSize方法添加一个线程工作,这个线程工作完成了,不是立即就退出的,它要接着取任务,取不到任务,就等待设定的超时时间后退出,同时从缓存线程池中移除此线程。(2)其他任务大部分情况和第一个任务一样,是进不去,在有大量并发的情况下,是可能拿到任务的,这时候又要分两种情况,如果线程池中没有可用线程,则新建线程执行,如果有可用进程,刚直接在可用线程中执行任务

问题二:工作线程的重用其实是在内部类work中的run方法,如下,可以看到work类-工作线程是在不断的从队列中取任务的,想详细了解怎么取任务的可以细看下getTask方法,这样一个循环就保证了工作线程的重用,即线程执行完一个任务后,可以执行下一个,那是不是会造成死循环呢?请看问题三

复制代码
/**
         * Main run loop
         */
        public void run() {
            try {
                Runnable task = firstTask;
                firstTask = null;
                while (task != null || (task = getTask()) != null) {
                    runTask(task);
                    task = null;
                }
            } finally {
                workerDone(this);
            }
        }
复制代码

问题三:移除60s未使用的线程,就是在getTask方法中,下面这句是getTask等待取任务的过程,可以看到在keepAliveTime的时间内,如果没有任务进来(通过execute提前),那么这个线程会在work类的run方法中的finally中,把自己从线程池中移除,并把task置为空。ok,成功解决问题三。

......
    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
......

回顾整个线程池的工作原理,其实不同的线程池从构造方法上来看,就是核心线程数和最大线程数以及工作队列的不同,其中队列的应用堪称精妙,使用不同的组合就可以达到不同的效果,整个线程池设计的非常巧妙,一个类实现几种不同线程池的工作,经典。

分享到:
评论

相关推荐

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

    ### JAVA线程池原理及几种线程池类型的详细介绍 #### 一、线程池的引入背景及重要性 在现代软件开发中,特别是在基于Java的应用程序设计中,线程池技术已经成为提高系统性能和资源利用率的关键手段之一。线程池...

    Java concurrency线程池之线程池原理(一)_动力节点Java学院整理

    Java concurrency线程池之线程池原理(一)_动力节点Java学院整理,动力节点口口相传的Java黄埔军校

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

    Java线程池是一种高效管理线程的工具,它允许开发者预先创建一组线程,并复用它们来处理任务,从而降低了创建和销毁线程的开销。线程池的使用尤其适用于处理大量短小任务的场景,例如Web服务器、数据库服务器等。在...

    JAVA线程池原理实例详解

    JAVA线程池原理实例详解 JAVA线程池是java中的一种高效的线程管理机制,它可以控制线程的创建、销毁和复用,从而提高系统的性能和可靠性。下面我们将详细介绍JAVA线程池的原理、创建、使用方法及相关注意事项。 一...

    java线程池封装j

    本文将深入探讨Java线程池的原理、封装以及相关知识点。 ### 1. Java线程池概念 Java线程池由`java.util.concurrent`包中的`ExecutorService`接口和其子类实现。其中,最常用的是`ThreadPoolExecutor`类,它提供了...

    Java 线程池的原理与实现

    理解Java线程池的原理和实现,可以帮助我们更有效地管理并发任务,提升系统性能,同时避免资源浪费和线程安全问题。在实际开发中,合理配置线程池参数,结合业务场景选择合适的线程池类型,是优化系统性能的关键步骤...

    JAVA线程池的原理与实现.pdf

    Java线程池是一种高效利用系统资源、管理并发执行任务的机制。...总的来说,理解Java线程池的工作原理和实现对于优化并发应用程序至关重要,它可以帮助我们更好地控制系统的并发度,提高系统的响应速度和资源利用率。

    Java常用线程池原理及使用方法解析

    Java线程池是一种高效管理线程的工具,它允许开发者预先创建一组线程,当需要执行新任务时,线程池会从池中选择一个空闲线程来执行任务,而不是每次都创建新的线程。线程池的使用有助于减少线程创建和销毁的开销,...

    深入探索:Java线程池的工作原理与实践

    本文将深入探讨Java线程池的工作原理,并通过实际代码示例,展示如何高效地使用线程池。 Java线程池是并发编程中的一个重要工具,它通过减少线程创建和销毁的开销,提高了程序的性能和资源利用率。理解线程池的...

    自定义实现Java线程池

    ### 自定义实现Java线程池 #### 一、概述 在深入探讨自定义Java线程池之前,我们先简要回顾一下线程池的基本概念及其重要性。线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动...

    Java 线程池原理深入分析

    总结Java线程池是Java多线程编程的重要工具,通过合理的配置和使用,可以有效地管理和调度线程,提高系统性能。理解线程池的工作原理和参数配置,对于编写高效、稳定的多线程程序至关重要。在实际应用中,应根据任务...

    Java线程池文档

    Java线程池是一种高效管理线程的机制,它允许开发者预先设定线程的数量,并通过池化的方式重用已创建的线程,以提高系统性能,减少线程的创建和销毁开销。线程池在Java中是通过`java.util.concurrent`包下的`...

    java多线程详解,线程池原理,8种锁,java内存模型......

    首先希望大家喜欢我制作的文档,如果文档中有什么误解的地方,望告诉一下,5分是也不多,是系统默认的,那么就5分咯,java多线程详解,线程池原理,8种锁,java内存模型......

    java线程池实例

    Java线程池是一种高效管理线程资源的工具,它通过维护一组可重用的线程来减少创建和销毁线程的开销。在Java中,`java.util.concurrent`包提供了`ExecutorService`接口和它的实现类,如`ThreadPoolExecutor`,来支持...

    深入理解Java线程池(PPT:原理+代码)

    通过剖析Java中线程池的原理,解读Java线程池源码,并给出线程池调用的示例,帮助理解线程池的基本原理。

    java 线程池实现多并发队列后进先出

    Java线程池是一种高效管理并发任务的机制,它允许开发者预先配置一定数量的线程,以便在处理多个并发任务时能有效地复用这些线程,从而避免了频繁创建和销毁线程带来的开销。在Java中,`java.util.concurrent`包下的...

    JAVA线程池例子

    Java线程池是一种高效管理线程资源的技术,它允许开发者创建一组可重用的工作线程,从而避免频繁地创建和销毁线程带来的性能开销。线程池在Java中主要通过`java.util.concurrent`包中的`ExecutorService`接口及其...

    基于Java线程池技术的数据爬虫设计与实现.pdf

    本文所提及的基于Java线程池技术的数据爬虫设计与实现,不仅涉及到了数据爬虫的原理和架构,还包括了多线程编程的知识点,以及线程池技术在数据爬虫中的具体应用。 首先,数据爬虫的基本原理是模拟用户的点击行为,...

    Java线程池及观察者模式解决多线程意外死亡重启问题

    Java线程池是Java并发编程中的重要组成部分,它允许开发者高效地管理多个并发执行的线程,有效地控制系统的资源消耗,提高系统性能和稳定性。在Java中,`java.util.concurrent`包提供了`ExecutorService`接口及其...

    鸟之家破解器源码

    鸟之家破解器源码

Global site tag (gtag.js) - Google Analytics