`
NiuBilityMan
  • 浏览: 2318 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

【Java-线程】ThreadPoolExecutor介绍与实例

    博客分类:
  • Java
阅读更多
Java 5 开始,Java 提供了自己的线程池。线程池就是一个线程的容器,每次只执行额定数量的线程。 java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。它很灵活,但使用起来也比较复杂,本文就对其做一个介绍。
 
  首先是构造函数。以最简单的构造函数为例:
[java]
  public ThreadPoolExecutor(   
              int corePoolSize,   
              int maximumPoolSize,   
              long keepAliveTime,   
              TimeUnit unit,   
              BlockingQueue workQueue)  
      public ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue)
  看起来挺复杂的。这里介绍一下。

corePoolSize 指的是保留的线程池大小。
maximumPoolSize 指的是线程池的最大大小。
keepAliveTime 指的是空闲线程结束的超时时间。
unit 是一个枚举,表示 keepAliveTime 的单位。
workQueue 表示存放任务的队列。
我们可以从线程池的工作过程中了解这些参数的意义。线程池的工作过程如下:
 
  1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。
2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:
     a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
     b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。
     c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;
     d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
这样的过程说明,并不是先加入任务就一定会先执行。假设队列大小为 10,corePoolSize 为 3,maximumPoolSize 为 6,那么当加入 20 个任务时,执行的顺序就是这样的:首先执行任务 1、2、3,然后任务 4~13 被放入队列。这时候队列满了,任务 14、15、16 会被马上执行,而任务 17~20 则会抛出异常。最终顺序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。下面是一个线程池使用的例子:

[java]
  public static void main(String[] args) {   
      BlockingQueue queue = new LinkedBlockingQueue();   
      ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.DAYS, queue);   
      
      for (int i = 0; i < 20; i++) {   
          executor.execute(new Runnable() {   
      
              public void run() {   
                  try {   
                      Thread.sleep(1000);   
                  } catch (InterruptedException e) {   
                      e.printStackTrace();   
                  }   
                  System.out.println(String.format("thread %d finished", this.hashCode()));   
              }   
          });   
      }   
      executor.shutdown();   
  }
  对这个例子的说明如下:
1、BlockingQueue 只是一个接口,常用的实现类有 LinkedBlockingQueue 和 ArrayBlockingQueue。用 LinkedBlockingQueue 的好处在于没有大小限制。这样的话,因为队列不会满,所以 execute() 不会抛出异常,而线程池中运行的线程数也永远不会超过 corePoolSize 个,keepAliveTime 参数也就没有意义了。
2、shutdown() 方法不会阻塞。调用 shutdown() 方法之后,主线程就马上结束了,而线程池会继续运行直到所有任务执行完才会停止。如果不调用 shutdown() 方法,那么线程池会一直保持下去,以便随时添加新的任务。
到这里对于这个线程池还只是介绍了一小部分。ThreadPoolExecutor 具有很强的可扩展性,不过扩展它的前提是要熟悉它的工作方式。
 
  java.util.concurrent.ThreadPoolExecutor 类提供了丰富的可扩展性。你可以通过创建它的子类来自定义它的行为。例如,我希望当每个任务结束之后打印一条消息,但我又无法修改任务对象,那么我可以这样写:
 
  [java]
  ThreadPoolExecutor executor = new ThreadPoolExecutor(size, maxSize, 1, TimeUnit.DAYS, queue) {
      @Override
      protected void afterExecute(Runnable r, Throwable t) {
          System.out.println("Task finished.");
      }
  };<span style="font-family: Arial; text-indent: 2em;"> </span>
  除了 afterExecute 方法之外,ThreadPoolExecutor 类还有 beforeExecute() 和 terminated() 方法可以重写,分别是在任务执行之前和整个线程池停止之后执行。
 
  
  除了可以添加任务执行前后的动作之外, ThreadPoolExecutor 还允许你自定义当添加任务失败后的执行策略。你可以调用线程池的 setRejectedExecutionHandler() 方法,用自定义的 RejectedExecutionHandler 对象替换现有的策略。 ThreadPoolExecutor 提供 4 个现有的策略,分别是:

ThreadPoolExecutor.AbortPolicy:表示拒绝任务并抛出异常
ThreadPoolExecutor.DiscardPolicy:表示拒绝任务但不做任何动作
ThreadPoolExecutor.CallerRunsPolicy:表示拒绝任务,并在调用者的线程中直接执行该任务
ThreadPoolExecutor.DiscardOldestPolicy:表示先丢弃任务队列中的第一个任务,然后把这个任务加进队列。
这里是一个例子:
[java]
  ThreadPoolExecutor executor = new ThreadPoolExecutor(size, maxSize, 1, TimeUnit.DAYS, queue);
      executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
  除此之外,你也可以通过实现 RejectedExecutionHandler 接口来编写自己的策略。下面是一个例子:
 
  [java]
  ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 6, 1, TimeUnit.SECONDS, queue,
          new RejectedExecutionHandler() {
              public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                  System.out.println(String.format("Task %d rejected.", r.hashCode()));
              }
          }
  );

分享到:
评论

相关推荐

    java 线程池例子ThreadPoolExecutor

    Java 线程池例子 ThreadPoolExecutor Java 中的线程池是指一个容器,里面包含了多个线程,这些线程可以重复使用,以避免频繁创建和销毁线程的开销。ThreadPoolExecutor 是 Java 中一个非常重要的线程池实现类,它...

    经典Java --线程

    Java线程是多任务编程的重要概念,它允许程序同时执行多个独立的任务,从而提升程序的效率和响应性。在Java中,线程可以分为两类:用户线程和守护线程。用户线程是应用程序的主要执行部分,而守护线程则是为用户线程...

    java多线程的讲解和实战

    6. **线程池**:Java提供`ExecutorService`和`ThreadPoolExecutor`来管理和控制线程,线程池可以有效地复用线程,减少创建和销毁线程的开销,提高系统效率。常用的接口有`Executors`,可以创建固定大小、单线程、...

    人工智能-项目实践-多线程-Java多线程高并发实例.zip

    在本项目实践中,我们将深入探讨Java中的多线程与高并发技术,特别是在人工智能领域的应用。Java作为一种广泛应用的编程语言,其强大的并发处理能力是其在大规模数据处理和高性能计算场景中备受青睐的原因之一。本...

    JAVA多线程的实例

    Java多线程是Java编程中的重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应性。在Java中,实现多线程有两种主要方式:通过实现`Runnable`接口或者继承`Thread`类。 首先,让我们从创建线程开始。当你...

    java多线程编程实例_Source

    Java的ExecutorService和ThreadPoolExecutor提供线程池管理,能有效控制并发量,防止过多线程导致资源浪费。实例会展示如何创建线程池,调整线程池参数,以及处理定时任务和延迟任务。 四、并发集合 Java并发包...

    《Java多线程编程实例》随书源码

    - 新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、等待(Waiting)、超时等待(Timed Waiting)和终止(Terminated)是Java线程的六种状态。 通过《Java多线程编程实例》随书源码,读者可以...

    java常见面试题---线程篇

    以下是一些关于Java线程的常见面试知识点,这些内容可能出现在线程.doc文档中: 1. **线程的创建方式**: - 实现`Runnable`接口:创建一个类实现`Runnable`接口,并重写`run()`方法,然后将实例传递给`Thread`类的...

    Java-Java线程编程教程

    Java线程编程是Java开发中的重要组成部分,尤其在如今并发处理和高性能系统设计中不可或缺。本教程将深入探讨Java多线程的相关概念、原理及实战技巧。 首先,我们需要理解什么是线程。线程是程序执行的基本单元,一...

    java多线程编程实例 (源程序)

    - Java线程有10个优先级,默认是Thread.NORM_PRIORITY(5)。但优先级并不保证执行顺序,只是影响调度概率。 7. **守护线程(Daemon)** - 守护线程不会阻止JVM的退出,常用于后台服务,如垃圾回收。 8. **线程池*...

    Java多线程编程实例

    本书“Java多线程编程实例”深入浅出地讲解了如何在Java环境中实现多线程操作,尽管出版时间较早,但其内容的经典性和实用性使其在现代开发中仍具有极高的参考价值。 首先,我们要理解Java中的线程是如何创建的。...

    java多线程测试实例

    - `ExecutorService`和`ThreadPoolExecutor`是Java并发库中的线程池工具,它们能有效管理线程生命周期,提高系统效率,避免大量线程创建销毁带来的开销。 8. **死锁(Deadlock)** - 当两个或更多线程互相等待...

    java线程实例 各种小Demo

    Java线程是多任务编程的重要概念,它允许程序同时执行多个独立的任务,从而...在"线程池.rar"和"线程实例"这两个文件中,你可以找到关于这些概念的具体示例代码,通过学习和实践,可以深入理解Java线程的运用和管理。

    狂神说Java-多线程课程全部代码.rar

    总之,《狂神说Java-多线程课程全部代码》这个资源提供了丰富的多线程和并发编程实例,对于希望提升Java并发编程技能的开发者来说是一份宝贵的参考资料。通过学习和实践其中的代码,你将能够更好地理解和掌握Java多...

    java-Thread-study-summary.zip_java 多线程

    Java线程有10个优先级,`MIN_PRIORITY`(1),`NORM_PRIORITY`(5)和`MAX_PRIORITY`(10)。较高的优先级并不意味着线程一定先执行,而是增加了获取CPU资源的概率。 5. **守护线程(Daemon)** 守护线程是支持...

    java多线程实现大批量数据导入源码

    在Java编程中,多线程技术是处理大数据批量导入或导出的重要手段。它能有效提升程序执行效率,尤其在数据库操作这样的I/O密集型任务中。本项目以"java多线程实现大批量数据导入源码"为题,旨在通过多线程策略将大量...

    java多线程Demo

    Java线程有10个优先级(MIN_PRIORITY, NORM_PRIORITY, MAX_PRIORITY),默认优先级是NORM_PRIORITY。但是,线程优先级并不保证绝对的执行顺序,操作系统调度策略可能影响实际执行顺序。 7. join()方法: 一个线程...

    彻底明白Java的多线程-线程间的通信.doc

    最后,`ExecutorService`和`ThreadPoolExecutor`提供了一种管理线程池的机制,它们可以有效地调度和控制线程,提高系统资源利用率,并简化线程生命周期的管理。 总之,理解Java的多线程以及线程间的通信是开发高效...

    Java多线程编程实战指南-核心篇

    本指南将通过实例分析和实践演练,让你深入理解多线程的原理与应用。 首先,我们要了解Java中的线程模型。Java通过Thread类来表示线程,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈和堆。线程的创建可以...

    Java 模拟线程并发

    此外,Java 5引入了java.util.concurrent并发包,提供了更高级的线程管理工具,如ExecutorService、ThreadPoolExecutor和Future。ExecutorService允许我们创建线程池,有效地管理线程生命周期,避免频繁创建和销毁...

Global site tag (gtag.js) - Google Analytics