`

线程池系列一:线程池作用及Executors方法讲解

    博客分类:
  • Java
 
阅读更多
from :   http://zy116494718.iteye.com/blog/1704344


线程池的作用:
     线程池作用就是限制系统中执行线程的数量。
     根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程 排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程 池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

为什么要用线程池:
减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)
ThreadGroup与ThreadPoolExecutor的区别

我自己的理解也是一直以为ThreadGroup就是ThreadPoolExecutor(线程池),这是一个非常大的误会,最近把两者仔细分析了下。 线程组表示一个线程的集合。此外,线程组也可以包含其他线程组。线程组构成一棵树,在树中,除了初始线程组外,每个线程组都有一个父线程组。允许线程访问 有关自己的线程组的信息,但是不允许它访问有关其线程组的父线程组或其他任何线程组的信息;线程消耗包括内存和其它系统资源在内的大量资源。除了 Thread 对象所需的内存之外,每个线程都需要两个可能很大的执行调用堆栈。除此以外,JVM 可能会为每个 Java 线程创建一个本机线程,这些本机线程将消耗额外的系统资源。最后,虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性 能。线程池是因为线程的生成关闭很浪费资源 所以不要频繁的操作 线程次 就是管理线程的地方 不用了它可以让它休眠也就是他替你管理线程 而且比你管理的要好的多。线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其 好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调 整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。

Executor详解:

Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。ThreadPoolExecutor是Executors类的底层实现。我们先介绍下Executors。

Sun在Java5中,对Java线程的类库做了大量的扩展,其中线程池就是Java5的新特征之一,除了线程池之外,还有很多多线程相关的内容,为多线程的编程带来了极大便利。为了编写高效稳定可靠的多线程程序,线程部分的新增内容显得尤为重要。

  有关Java5线程新特征的内容全部在java.util.concurrent下面,里面包含数目众多的接口和类,熟悉这部分API特征是一项艰难的学习过程。目前有关这方面的资料和书籍都少之又少,大所属介绍线程方面书籍还停留在java5之前的知识层面上。

  当然新特征对做多线程程序没有必须的关系,在java5之前通用可以写出很优秀的多线程程序。只是代价不一样而已。

  线程池的基本思想还是一种对象池的思想,开辟一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理。当有线程任务时,从池中取一个,执行完成后线程对象归池,这样可以避免反复创建线程对象所带来的性能开销,节省了系统的资源。

  在Java5之前,要实现一个线程池是相当有难度的,现在Java5为我们做好了一切,我们只需要按照提供的API来使用,即可享受线程池带来的极大便利。

  Java5的线程池分好多种:固定尺寸的线程池、可变尺寸连接池。

  在使用线程池之前,必须知道如何去创建一个线程池,在Java5中,需要了解的是java.util.concurrent.Executors类的API,这个类提供大量创建连接池的静态方法,是必须掌握的。

实例:

一、固定大小的线程池

Java代码  收藏代码
import java.util.concurrent.Executors; 
  import java.util.concurrent.ExecutorService; 
  /**
  * Java线程:线程池-
  *
  * @author Administrator 2009-11-4 23:30:44
  */ 
  public class Test { 
  public static void main(String[] args) { 
  //创建一个可重用固定线程数的线程池 
  ExecutorService pool = Executors.newFixedThreadPool(2); 
  //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 
  Thread t1 = new MyThread(); 
  Thread t2 = new MyThread(); 
  Thread t3 = new MyThread(); 
  Thread t4 = new MyThread(); 
  Thread t5 = new MyThread(); 
  //将线程放入池中进行执行 
  pool.execute(t1); 
  pool.execute(t2); 
  pool.execute(t3); 
  pool.execute(t4); 
  pool.execute(t5); 
  //关闭线程池 
  pool.shutdown(); 
  } 
  } 
  class MyThread extends Thread{ 
  @Override 
  public void run() { 
  System.out.println(Thread.currentThread().getName()+"正在执行。。。"); 
  } 
  }  




  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-2正在执行。。。
  Process finished with exit code 0


  二、单任务线程池

  在上例的基础上改一行创建pool对象的代码为:

  //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
Java代码  收藏代码
ExecutorService pool = Executors.newSingleThreadExecutor();  


  输出结果为:


      pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  Process finished with exit code 0


  对于以上两种连接池,大小都是固定的,当要加入的池的线程(或者任务)超过池最大尺寸时候,则入此线程池需要排队等待。

  一旦池中有线程完毕,则排队等待的某个线程会入池执行。

  三、可变尺寸的线程池

  与上面的类似,只是改动下pool的创建方式:

  //创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
Java代码  收藏代码
ExecutorService pool = Executors.newCachedThreadPool();  


  pool-1-thread-5正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-4正在执行。。。
  pool-1-thread-3正在执行。。。
  pool-1-thread-2正在执行。。。
  Process finished with exit code 0


  四、延迟连接池

Java代码  收藏代码
import java.util.concurrent.Executors; 
  import java.util.concurrent.ScheduledExecutorService; 
  import java.util.concurrent.TimeUnit; 
  /**
  * Java线程:线程池-
  *
  * @author Administrator 2009-11-4 23:30:44
  */ 
  public class Test { 
  public static void main(String[] args) { 
  //创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 
  ScheduledExecutorService pool = Executors.newScheduledThreadPool(2); 
  //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 
  Thread t1 = new MyThread(); 
  Thread t2 = new MyThread(); 
  Thread t3 = new MyThread(); 
  Thread t4 = new MyThread(); 
  Thread t5 = new MyThread(); 
  //将线程放入池中进行执行 
  pool.execute(t1); 
  pool.execute(t2); 
  pool.execute(t3); 
  //使用延迟执行风格的方法 
  pool.schedule(t4, 10, TimeUnit.MILLISECONDS); 
  pool.schedule(t5, 10, TimeUnit.MILLISECONDS); 
  //关闭线程池 
  pool.shutdown(); 
  } 
  } 
  class MyThread extends Thread { 
  @Override 
  public void run() { 
  System.out.println(Thread.currentThread().getName() + "正在执行。。。"); 
  } 
  }  



    pool-1-thread-1正在执行。。。
  pool-1-thread-2正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-2正在执行。。。
  Process finished with exit code 0


  五、单任务延迟连接池

  在四代码基础上,做改动

  //创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。

 

Java代码  收藏代码
ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();  

  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-1正在执行。。。
  Process finished with exit code 0


  六、自定义线程池

 

Java代码  收藏代码
import java.util.concurrent.ArrayBlockingQueue; 
  import java.util.concurrent.BlockingQueue; 
  import java.util.concurrent.ThreadPoolExecutor; 
  import java.util.concurrent.TimeUnit; 
  /**
  * Java线程:线程池-自定义线程池
  *
  * @author Administrator 2009-11-4 23:30:44
  */ 
  public class Test { 
  public static void main(String[] args) { 
  //创建等待队列 
  BlockingQueue bqueue = new ArrayBlockingQueue(20); 
  //创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 
  ThreadPoolExecutor pool = new ThreadPoolExecutor(2,3,2,TimeUnit.MILLISECONDS,bqueue); 
  //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 
  Thread t1 = new MyThread(); 
  Thread t2 = new MyThread(); 
  Thread t3 = new MyThread(); 
  Thread t4 = new MyThread(); 
  Thread t5 = new MyThread(); 
  Thread t6 = new MyThread(); 
  Thread t7 = new MyThread(); 
  //将线程放入池中进行执行 
  pool.execute(t1); 
  pool.execute(t2); 
  pool.execute(t3); 
  pool.execute(t4); 
  pool.execute(t5); 
  pool.execute(t6); 
  pool.execute(t7); 
  //关闭线程池 
  pool.shutdown(); 
  } 
  } 
  class MyThread extends Thread { 
  @Override 
  public void run() { 
  System.out.println(Thread.currentThread().getName() + "正在执行。。。"); 
  try { 
  Thread.sleep(100L); 
  } catch (InterruptedException e) { 
  e.printStackTrace(); 
  } 
  } 
  }  



 
      pool-1-thread-1正在执行。。。
  pool-1-thread-2正在执行。。。
  pool-1-thread-2正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-2正在执行。。。
  pool-1-thread-1正在执行。。。
  pool-1-thread-2正在执行。。。
  Process finished with exit code 0


  创建自定义线程池的构造方法很多,本例中参数的含义如下:


    ThreadPoolExecutor
  public ThreadPoolExecutor(int corePoolSize,
  int maximumPoolSize,
  long keepAliveTime,
  TimeUnit unit,
  BlockingQueue workQueue)


  用给定的初始参数和默认的线程工厂及处理程序创建新的 ThreadPoolExecutor。使用 Executors 工厂方法之一比使用此通用构造方法方便得多。

  参数:

  corePoolSize - 池中所保存的线程数,包括空闲线程。

  maximumPoolSize - 池中允许的最大线程数。

  keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

  unit - keepAliveTime 参数的时间单位。

  workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。

  抛出:

  IllegalArgumentException - 如果 corePoolSize 或 keepAliveTime 小于零,或者 maximumPoolSize 小于或等于零,或者 corePoolSize 大于 maximumPoolSize。

  NullPointerException - 如果 workQueue 为 null

  自定义连接池稍微麻烦些,不过通过创建的ThreadPoolExecutor线程池对象,可以获取到当前线程池的尺寸、正在执行任务的线程数、工作队列等等。
分享到:
评论

相关推荐

    线程池管理多线程上传

    - **创建线程池**:通过`ExecutorService`接口实例化,如`Executors`类提供的`newFixedThreadPool`、`newCachedThreadPool`等静态方法。 - **提交任务**:使用`ExecutorService`的`execute()`方法提交`Runnable`或...

    socket 线程池实现

    Socket线程池是一种高效管理网络连接的技术,它结合了Socket通信和线程池的设计思想,以提高系统的并发处理能力和资源利用率。在Java等编程语言中,我们常常利用线程池来处理大量的并发Socket连接,避免频繁创建和...

    Java四种常用线程池的详细介绍

    3.可重用固定个数的线程池(Executors.newFixedThreadPool(int n)):创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程。 4._SCHEDULED线程池(Executors.newScheduledThreadPool(int ...

    socket 线程池实现(已经在项目中应用)

    你可以使用`Executors`工具类的静态方法来创建线程池,例如`newFixedThreadPool(int nThreads)`,它会创建一个固定大小的线程池,当有新连接请求时,线程池中的空闲线程会处理这个请求,如果所有线程都在忙碌,新...

    day19_阻塞队列、线程池、File类、递归.pdf

    3. **SynchronousQueue**:一个特殊的阻塞队列,它不存储元素,每个put操作必须等待一个take操作,反之亦然。SynchronousQueue提供了公平锁和非公平锁的选项,适用于需要精确控制线程间通信的场景。 以下是一些常用...

    java多线程的讲解和实战

    常用的接口有`Executors`,可以创建固定大小、单线程、定时任务等类型的线程池。 7. **死锁与活锁**:当两个或更多线程互相等待对方释放资源而无法继续执行时,就会发生死锁。活锁则是线程虽然没有阻塞,但由于某种...

    android listview异步加载图片实例(线程池+数据库+本地保存)

    1. 创建线程池:使用`Executors`静态工厂方法创建一个固定大小的线程池,如`ExecutorService executor = Executors.newFixedThreadPool(poolSize);` 2. 实现图片下载接口:定义一个接口,包含下载图片的方法,如`...

    Android异步加载图像小结 (含线程池,缓存方法)(实用1).zip

    本篇将详细讲解如何实现Android中的异步图像加载,包括使用线程池和缓存策略。 首先,我们需要理解为什么需要异步加载。在Android中,主线程负责UI更新,如果在主线程中执行耗时操作(如网络请求或解码图片),会...

    Android异步加载图像小结 (含线程池,缓存方法).zip

    本篇将对Android中的异步图像加载进行详细讲解,包括线程池的使用和缓存方法。 1. **异步加载图像的重要性** - 在Android中,主线程负责更新UI,如果在主线程中执行耗时操作(如网络请求或图片解码),会导致应用...

    Android 下soap线程池并发请求

    本篇文章将详细讲解如何在Android环境下实现SOAP线程池并发请求,以提高应用性能和用户体验。 一、SOAP基础 SOAP是基于XML的协议,它允许服务提供商和消费者通过HTTP、SMTP等传输协议进行通信。在Android中,我们...

    java多线程断点下载

    例如,可以使用`Executors.newFixedThreadPool(int corePoolSize)`创建固定大小的线程池。 3. **分配下载任务**:将文件分成若干个块,每个块对应一个线程进行下载。块的大小应该根据文件大小和网络状况来调整,以...

    AQS和JUC知识点讲解

    2. **线程池**:Executor框架是JUC的核心,它提供ThreadPoolExecutor和Executors类来创建和管理线程池。线程池可以有效地重用已存在的线程,减少创建和销毁线程的开销,提高系统性能。 3. **并发工具类**:如...

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

    本文将详细讲解ExecutorService的原理、使用场景以及如何通过Executors类创建线程池。 1. 为什么使用线程池 线程池的主要目的是为了优化线程的生命周期管理。在处理大量并发任务时,如果每个任务都单独创建线程,...

    JAVA多线程模式高清版+DEMO

    - `Executors`:提供创建线程池的静态工厂方法。 6. **并发工具类**: - `CountDownLatch`:用于多线程同步,计数器减至零后所有线程继续执行。 - `CyclicBarrier`:多线程到达屏障后一起继续,可重用。 - `...

    java线程入门,一本简绍java线程的书

    6. **线程池**:深入讨论`ExecutorService`、`ThreadPoolExecutor`和`Executors`,如何配置线程池,以及它们在管理线程资源上的优势。 7. **线程优先级**:理解线程优先级的概念,以及`setPriority()`方法的使用。 ...

    Java公司培训经典学习笔记

    - **线程池**:ExecutorService、ThreadPoolExecutor和Executors的使用,以及线程池的参数调整。 7. **网络编程** - **套接字编程**:Socket和ServerSocket的使用,以及TCP和UDP的区别。 - **HTTP通信**:利用...

    后端开发-06-线程执行带有参数的任务.ev4.rar

    本资源“后端开发-06-线程执行带有参数的任务.ev4.rar”可能是一个教学视频或课程,专注于讲解如何在后端程序中使用线程来处理具有输入参数的任务。下面将详细探讨这个主题。 1. **线程基础** - **线程概念**:...

    多线程与线程池技术详解(图书配套)

    在实际开发中,Java的Executor框架提供了多种预定义的线程池,如`Executors.newFixedThreadPool`用于创建固定大小的线程池,`Executors.newSingleThreadExecutor`创建只有一个线程的线程池,以及`Executors....

    android多线程demo(很清晰很详细)

    - **Executors**:提供预定义的线程池,如newFixedThreadPool, newSingleThreadExecutor等。 8. **Demo分析**: 这个示例可能包含以上各种多线程技术的实践,通过阅读源码,我们可以了解如何在Android中实际运用...

Global site tag (gtag.js) - Google Analytics