知识大全 1100行代码设计一个线程池

Posted

篇首语:男儿欲遂平生志,六经勤向窗前读。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 1100行代码设计一个线程池相关的知识,希望对你有一定的参考价值。

  在现代的操作系统中 有一个很重要的概念――线程 几乎所有目前流行的操作系统都支持线程 线程来源于操作系统中进程的概念 进程有自己的虚拟地址空间以及正文段 数据段及堆栈 而且各自占有不同的系统资源(例如文件 环境变量等等) 与此不同 线程不能单独存在 它依附于进程 只能由进程派生 如果一个进程派生出了两个线程 那这两个线程共享此进程的全局变量和代码段 但每个线程各拥有各自的堆栈 因此它们拥有各自的局部变量 线程在UNIX系统中还被进一步分为用户级线程(由进程自已来管理)和系统级线程(由操作系统的调度程序来管理)     既然有了进程 为什么还要提出线程的概念呢?因为与创建一个新的进程相比 创建一个线程将会耗费小得多的系统资源 对于一些小型的应用 可能感觉不到这点 但对于那些并发进程数特别多的应用 使用线程会比使用进程获得更好的性能 从而降低操作系统的负担 另外 线程共享创建它的进程的全局变量 因此线程间的通讯编程会更将简单 完全可以抛弃传统的进程间通讯的IPC编程 而采用共享全局变量来进行线程间通讯     有了上面这个概念 我们下面就进入正题 来看一下线程池究竟是怎么一回事?其实线程池的原理很简单 类似于操作系统中的缓冲区的概念 它的流程如下 先启动若干数量的线程 并让这些线程都处于睡眠状态 当客户端有一个新请求时 就会唤醒线程池中的某一个睡眠线程 让它来处理客户端的这个请求 当处理完这个请求后 线程又处于睡眠状态 可能你也许会问 为什么要搞得这么麻烦 如果每当客户端有新的请求时 我就创建一个新的线程不就完了?这也许是个不错的方法 因为它能使得你编写代码相对容易一些 但你却忽略了一个重要的问题――性能!就拿我所在的单位来说 我的单位是一个省级数据大集中的银行网络中心 高峰期每秒的客户端请求并发数超过 如果为每个客户端请求创建一个新线程的话 那耗费的CPU时间和内存将是惊人的 如果采用一个拥有 个线程的线程池 那将会节约大量的的系统资源 使得更多的CPU时间和内存用来处理实际的商业应用 而不是频繁的线程创建与销毁     既然一切都明白了 那我们就开始着手实现一个真正的线程池吧 线程编程可以有多种语言来实现 例如C C++ java等等 但不同的操作系统提供不同的线程API接口 为了让你能更明白线程池的原理而避免陷入烦琐的API调用之中 我采用了JAVA语言来实现它 由于JAVA语言是一种跨平台的语言 因此你不必为使用不同的操作系统而无法编译运行本程序而苦恼 只要你安装了JDK 以上的版本 都能正确地编译运行本程序 另外JAVA语言本身就内置了线程对象 而且JAVA语言是完全面像对象的 因此能够让你更清晰地了解线程池的原理 如果你注意看一下本文的标题 你会发现整个示例程序的代码只有大约 行     本示例程序由三个类构成 第一个是TestThreadPool类 它是一个测试程序 用来模拟客户端的请求 当你运行它时 系统首先会显示线程池的初始化信息 然后提示你从键盘上输入字符串 并按下回车键 这时你会发现屏幕上显示信息 告诉你某个线程正在处理你的请求 如果你快速地输入一行行字符串 那么你会发现线程池中不断有线程被唤醒 来处理你的请求 在本例中 我创建了一个拥有 个线程的线程池 如果线程池中没有可用线程了 系统会提示你相应的警告信息 但如果你稍等片刻 那你会发现屏幕上会陆陆续续提示有线程进入了睡眠状态 这时你又可以发送新的请求了     第二个类是ThreadPoolManager类 顾名思义 它是一个用于管理线程池的类 它的主要职责是初始化线程池 并为客户端的请求分配不同的线程来进行处理 如果线程池满了 它会对你发出警告信息     最后一个类是SimpleThread类 它是Thread类的一个子类 它才真正对客户端的请求进行处理 SimpleThread在示例程序初始化时都处于睡眠状态 但如果它接受到了ThreadPoolManager类发过来的调度信息 则会将自己唤醒 并对请求进行处理   首先我们来看一下TestThreadPool类的源码     //TestThreadPool java   import java io *;         public class TestThreadPool      public static void main(String[] args)      try   BufferedReader br = new BufferedReader(new InputStreamReader(System in));   String s;   ThreadPoolManager manager = new ThreadPoolManager( );   while((s = br readLine()) != null)      manager process(s);      catch(IOException e)          由于此测试程序用到了输入输入类 因此第 行导入了JAVA的基本IO处理包 在第 行中 我们创建了一个名为manager的类 它给ThreadPoolManager类的构造函数传递了一个值为 的参数 告诉ThreadPoolManager类 我要一个有 个线程的池 给我创建一个吧!第 行至 行是一个无限循环 它用来等待用户的键入 并将键入的字符串保存在s变量中 并调用ThreadPoolManager类的process方法来将这个请求进行处理     下面我们再进一步跟踪到ThreadPoolManager类中去 以下是它的源代码     //ThreadPoolManager java   import java util *;         class ThreadPoolManager         private int maxThread;   public Vector vector;   public void setMaxThread(int threadCount)      maxThread = threadCount;         public ThreadPoolManager(int threadCount)      setMaxThread(threadCount);   System out println( Starting thread pool );   vector = new Vector();   for(int i = ; i <= 10; i++)  20   21 SimpleThread thread = new SimpleThread(i);  22 vector.addElement(thread);  23 thread.start();  24   25   26  27 public void process(String argument)  28   29 int i;  30 for(i = 0; i < vector.size(); i++)  31   32 SimpleThread currentThread = (SimpleThread)vector.elementAt(i);  33 if(!currentThread.isRunning())  34   35 System.out.println("Thread "+ (i+1) +" is processing:" +  argument);  36 currentThread.setArgument(argument);  37 currentThread.setRunning(true);  38 return;  39   40   41 if(i == vector.size())  42   43 System.out.println("pool is full, try in another time.");  44   45   46 //end of class ThreadPoolManager    我们先关注一下这个类的构造函数,然后再看它的process()方法。.WInGWIt.第16-24行是它的构造函数,首先它给ThreadPoolManager类的成员变量maxThread赋值,maxThread表示用于控制线程池中最大线程的数量。第18行初始化一个数组vector,它用来存放所有的SimpleThread类,这时候就充分体现了JAVA语言的优越性与艺术性:如果你用C语言的话,至少要写100行以上的代码来完成vector的功能,而且C语言数组只能容纳类型统一的基本数据类型,无法容纳对象。好了,闲话少说,第19-24行的循环完成这样一个功能:先创建一个新的SimpleThread类,然后将它放入vector中去,最后用thread.start()来启动这个线程,为什么要用start()方法来启动线程呢?因为这是JAVA语言中所规定的,如果你不用的话,那这些线程将永远得不到激活,从而导致本示例程序根本无法运行。  下面我们再来看一下process()方法,第30-40行的循环依次从vector数组中选取SimpleThread线程,并检查它是否处于激活状态(所谓激活状态是指此线程是否正在处理客户端的请求),如果处于激活状态的话,那继续查找vector数组的下一项,如果vector数组中所有的线程都处于激活状态的话,那它会打印出一条信息,提示用户稍候再试。相反如果找到了一个睡眠线程的话,那第35-38行会对此进行处理,它先告诉客户端是哪一个线程来处理这个请求,然后将客户端的请求,即字符串argument转发给SimpleThread类的setArgument()方法进行处理,并调用SimpleThread类的setRunning()方法来唤醒当前线程,来对客户端请求进行处理。    可能你还对setRunning()方法是怎样唤醒线程的有些不明白,那我们现在就进入最后一个类:SimpleThread类,它的源代码如下:    //SimpleThread.java  1 class SimpleThread extends Thread  2   3 private boolean runningFlag;  4 private String argument;  5 public boolean isRunning()  6   7 return runningFlag;  8   9 public synchronized void setRunning(boolean flag)  10   11 runningFlag = flag;  12 if(flag)  13 this.notify();  14   15  16 public String getArgument()  17   18 return this.argument;  19   20 public void setArgument(String string)  21   22 argument = string;  23   24  25 public SimpleThread(int threadNumber)  26   27 runningFlag = false;  28 System.out.println("thread " + threadNumber + "started.");  29   30  31 public synchronized void run()  32   33 try  34 wh cha138/Article/program/Java/gj/201311/27304

相关参考

知识大全 典型Java线程池的代码及其各部分功能介绍

典型Java线程池的代码及其各部分功能介绍  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  ()根

知识大全 一个非常简单和短小的线程池

    最近写了一个HTTP代理服务器发现访问网页时建立的连接很多消耗的线程也非常的多对于系统是一个不小的开销而且这些线程存在的时间都很短%以上的线程存在的时间

知识大全 学ui设计对代码感兴趣好转行做web前端吗

学ui设计对代码感兴趣好转行做web前端吗可以的。UI设计学习过程中有WEB前端的内容,新人需要按照中间的喜爱选择后期发展的细分岗位。UI设计主要学习平面设计、交互设计、WEB前端设计与实现、移动端设

知识大全 基于线程池的匹配文件数量计算

   构建一个新的线程的代价还是有些高的因为它涉及与操作系统的交互如果你的程序创建了大量生存期很短的线程那就应该使用线程池一个线程池包含大量准备运行的空闲线程你将一个Ru

知识大全 批处理程序中的“多线程”处理代码

大家都知道批处理中运行的都是一步步单进程执行 但如果进程执行比较慢如PING一个不通的IP地址那就会大大影响批处理程序的执行效率  如下内容将简单举例在WINDOWS下使用批处理做多进程并发

知识大全 使用匿名内部类在方法内部定义并启动线程

  本文代码展示了在一个方法中通过匿名内部类定义一个Thread并Override它的run()方法之后直接启动该线程  下面的代码展示了在一个方法中通过匿名内部类定义一个Thread并Overrid

知识大全 高级应用 java多线程设计模式详解之一

  线程的创建和启动    java语言已经内置了多线程支持所有实现Runnable接口的类都可被启动一个新线程新线程会执行该实例的run()方法当run()方法执行完毕后线程就结束了一旦一个线程执行

知识大全 多线程编程的设计模式 临界区模式

  临界区模式CriticalSectionPattern是指在一个共享范围中只让一个线程执行的模式它是所有其它多线程设计模式的基础所以我首先来介绍它把着眼点放在范围上这个模式叫临界区模式如果把作眼点

知识大全 20行代码实现的一个CSS覆蓋率测试脚本

20行代码实现的一个CSS覆蓋率测试脚本  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  docu

知识大全 java关于多线程的部分操作

  一般服务器端代码每次收到一个线程一个client就会产生  /************************开始监听**************************/  intport=;