线程池的介绍及简单实现

2016-02-19 14:58 8 1 收藏

今天图老师小编要跟大家分享线程池的介绍及简单实现,精心挑选的过程简单易学,喜欢的朋友一起来学习吧!

【 tulaoshi.com - 编程语言 】

  服务器程序利用线程技术响应客户请求已经司空见惯,可能您认为这样做效率已经很高,但您有没有想过优化一下使用线程的方法。该文章将向您介绍服务器程序如何利用线程池来优化性能并提供一个简单的线程池实现。

  线程池的技术背景

  在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想。

  目前,一些著名的大公司都特别看好这项技术,并早已经在他们的产品中应用该技术。比如IBM的WebSphere,IONA的Orbix 2000在SUN的 Jini中,Microsoft的MTS(Microsoft Transaction Server 2.0),COM+等。

  现在您是否也想在服务器程序应用该项技术?

  线程池技术如何提高服务器程序的性能

  我所提到服务器程序是指能够接受客户请求并能处理请求的程序,而不只是指那些接受网络客户请求的网络服务器程序。

  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。可以举一个简单的例子:

  假设在一台服务器完成一项任务的时间为T

   T1 创建线程的时间
   T2 在线程中执行任务的时间,包括线程间同步所需时间
   T3 线程销毁的时间

  显然T = T1+T2+T3。注意这是一个极度简化的假设。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。

  线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。

  线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。在看一个例子:

  假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。我们比较利用线程池技术和不利于线程池技术的服务器处理这些请求时所产生的线程总数。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目或者上限(以下简称线程池尺寸),而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池尺寸是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

  这些都是假设,不能充分说明问题,下面我将讨论线程池的简单实现并对该程序进行对比测试,以说明线程技术优点及应用领域。

  线程池的简单实现及对比测试

  一般一个简单线程池至少包含下列组成部分。

线程池管理器(ThreadPoolManager):用于创建并管理线程池 工作线程(WorkThread): 线程池中线程 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。 任务队列:用于存放没有处理的任务。提供一种缓冲机制。

  线程池管理器至少有下列功能:创建线程池,销毁线程池,添加新任务创建线程池的部分代码如下:

  


 
    //create threads
    synchronized(workThreadVector)
    {
      for(int j = 0; j i; j++)
      {
        threadNum++;
        WorkThread workThread = new WorkThread(taskVector, threadNum);
        workThreadVector.addElement(workThread);
      }
    }

  注意同步workThreadVector并没有降低效率,相反提高了效率,请参考Brian Goetz的文章。 销毁线程池的部分代码如下:

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  


 
    while(!workThreadVector.isEmpty())
    {
    if(debugLevel 2)
     System.out.println("stop:"+(i));
     i++;
      try
      {
        WorkThread workThread = (WorkThread)workThreadVector.remove(0);
        workThread.closeThread();
        continue;
      }
      catch(Exception exception)
      {
        if(debugLevel 2)
          exception.printStackTrace();
      }
      break;
    }
 

  添加新任务的部分代码如下:

  


 
    synchronized(taskVector)
    {
      taskVector.addElement(taskObj);
      taskVector.notifyAll();
    }
 

  工作线程是一个可以循环执行任务的线程,在没有任务时将等待。由于代码比较多在此不罗列.

  任务接口是为所有任务提供统一的接口,以便工作线程处理。任务接口主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等。在文章结尾有相关代码的下载。

  以上所描述的线程池结构很简单,一些复杂的线程池结构将不再此讨论。

  在下载代码中有测试驱动程序(TestThreadPool),我利用这个测试程序的输出数据统计出下列测试结果。测试有两个参数要设置:

线程池中线程数,即线程池尺寸。 要完成的任务数。

  分别将一个参数固定,另一个参数变动以考察两个参数所产生的不同结果。所用测试机器分别为普通PC机(Win2000 JDK1.3.1)和SUN服务器(Solaris Unix JDK1.3.1),机器配置在此不便指明。

  表1:测试数据及对应结果

  线程池尺寸任务数没有应用线程池所用的时间(单位:毫秒,OS:win)应用线程池所用的时间(单位:毫秒,OS:win)没有应用线程池所用的时间(单位:毫秒,OS:Solaris)应用线程池所用的时间(单位:毫秒,OS:Solaris)1500038961306513327250003455151622165945000342512054484338500034751605769147816500035052115785197032500034552516403875645000359550151821103128500035158815154405256500034953104550215895125000342554885667126216120022316220202113164201027101682020222416163020294816324020461081664602072199161281102014833516256201202521321651241140522382161024811711233610162048155280204513516409628742504828787

  图1.线程池的尺寸的对服务器程序的性能影响

  根据以上统计数据可得出下图:

  图2.任务数对服务器程序的冲击

  数据分析如下:

来源:http://www.tulaoshi.com/n/20160219/1608502.html

延伸阅读
标签: Java JAVA基础
使用 Java 编程语言实现线程 Java编程语言使多线程如此简单有效,以致于某些程序员说它实际上是自然的。尽管在 Java 中使用线程比在其他语言中要容易得多,仍然有恍└拍钚枰莆铡R亲〉囊患匾氖虑槭?main() 函数也是一个线程,并可用来做有用的工作。程序员只有在需要多个线程时才需要创建新的线程。 Thre...
标签: Web开发
注:以下内容基于IE中GIF的onload事件的基础上,故所有测试IE only 需要用到的几个图片 先看一个简单的事实: 代码如下: SCRIPT LANGUAGE="JavaScript" var img=new Image(); img.src="attachment/1178365293_0.gif"; img.onload=function() { alert("如要关闭请按住ESC键不放,并点击关闭按钮"); } /SCRIPT 如果不出所料...
贴在我们多线程 Java 编程论坛上最常见的问题之一是怎样创建线程池?。几乎在每个服务器应用程序中都会出现线程池和工作队列问题。本文中,Brian Goetz 探讨了线程池的动机、一些基本实现和调优技术以及一些要避免的常见危险。为什么要用线程池? 诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面...
多线程是一个比较轻量级的方法来实现单个应用程序内多个代码执行路径。 在系统级别内,程序并排执行,程序分配到每个程序的执行时间是基于该程序的所需时间和其他程序的所需时间来决定的。 然而,在每个程序内部,存在一个或者多个执行线程,它同时或在一个几乎同时发生的方式里执行不同的任务。 概要提示: iPhone中的线程应用并不是无...
  关于线程的参数(2.0)、“返回值”、及线程的中止 1.线程的参数: 有时候会想向辅助线程传递些信息,这里需要用到ParameterizedThreadStart 委托 示例:         private void btRunThread_Click(object sender, EventArgs e)         {   &nbs...

经验教程

163

收藏

24
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部