java 线程池

 

2008 - 08 - 02

创建Java线程池

博客分类: Java

线程池的作用:

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

 

为什么要用线程池:

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

线程池类

    

Java代码   收藏代码
  1. package  com.tdt.impl.ls;  
  2.   
  3. import  java.util.LinkedList;  
  4.   
  5. /**  
  6.  * @project LocationGateway  
  7.  * @author sunnylocus     
  8.  * @verson 1.0.0  
  9.  * @date   Aug 2, 2008  
  10.  * @jdk    1.4.2  
  11.  */   
  12. public   class  ThreadPool  extends  ThreadGroup {  
  13.     private   boolean  isClosed =  false ;   //线程池是否关闭    
  14.     private  LinkedList workQueue;       //工作队列   
  15.     private   static   int  threadPoolID =  1 ;   //线程池的id   
  16.     public  ThreadPool( int  poolSize) {   //poolSize 表示线程池中的工作线程的数量   
  17.   
  18.         super (threadPoolID +  "" );       //指定ThreadGroup的名称   
  19.         setDaemon(true );                //继承到的方法,设置是否守护线程池   
  20.         workQueue = new  LinkedList();   //创建工作队列   
  21.         for ( int  i =  0 ; i < poolSize; i++) {  
  22.             new  WorkThread(i).start();    //创建并启动工作线程,线程池数量是多少就创建多少个工作线程   
  23.         }  
  24.     }  
  25.       
  26.     /** 向工作队列中加入一个新任务,由工作线程去执行该任务*/   
  27.     public   synchronized   void  execute(Runnable task) {  
  28.         if (isClosed) {  
  29.             throw   new  IllegalStateException();  
  30.         }  
  31.         if (task !=  null ) {  
  32.             workQueue.add(task);//向队列中加入一个任务   
  33.             notify();           //唤醒一个正在getTask()方法中待任务的工作线程   
  34.         }  
  35.     }  
  36.       
  37.     /** 从工作队列中取出一个任务,工作线程会调用此方法*/   
  38.     private   synchronized  Runnable getTask( int  threadid)  throws  InterruptedException {  
  39.         while (workQueue.size() ==  0 ) {  
  40.             if (isClosed)  return   null ;  
  41.             System.out.println("工作线程" +threadid+ "等待任务..." );  
  42.             wait();             //如果工作队列中没有任务,就等待任务   
  43.         }  
  44.         System.out.println("工作线程" +threadid+ "开始执行任务..." );  
  45.         return  (Runnable) workQueue.removeFirst();  //反回队列中第一个元素,并从队列中删除   
  46.     }  
  47.       
  48.     /** 关闭线程池 */   
  49.     public   synchronized   void  closePool() {  
  50.         if (! isClosed) {  
  51.             waitFinish();        //等待工作线程执行完毕   
  52.             isClosed = true ;  
  53.             workQueue.clear();  //清空工作队列   
  54.             interrupt();        //中断线程池中的所有的工作线程,此方法继承自ThreadGroup类   
  55.         }  
  56.     }  
  57.       
  58.     /** 等待工作线程把所有任务执行完毕*/   
  59.     public   void  waitFinish() {  
  60.         synchronized  ( this ) {  
  61.             isClosed = true ;  
  62.             notifyAll();            //唤醒所有还在getTask()方法中等待任务的工作线程   
  63.         }  
  64.         Thread[] threads = new  Thread[activeCount()];  //activeCount() 返回该线程组中活动线程的估计值。   
  65.         int  count = enumerate(threads);  //enumerate()方法继承自ThreadGroup类,根据活动线程的估计值获得线程组中当前所有活动的工作线程   
  66.         for ( int  i = 0 ; i < count; i++) {  //等待所有工作线程结束   
  67.             try  {  
  68.                 threads[i].join();  //等待工作线程结束   
  69.             }catch (InterruptedException ex) {  
  70.                 ex.printStackTrace();  
  71.             }  
  72.         }  
  73.     }  
  74.   
  75.     /**  
  76.      * 内部类,工作线程,负责从工作队列中取出任务,并执行  
  77.      * @author sunnylocus  
  78.      */   
  79.     private   class  WorkThread  extends  Thread {  
  80.         private   int  id;  
  81.         public  WorkThread( int  id) {  
  82.             //父类构造方法,将线程加入到当前ThreadPool线程组中   
  83.             super (ThreadPool. this ,id+ "" );  
  84.             this .id =id;  
  85.         }  
  86.         public   void  run() {  
  87.             while (! isInterrupted()) {   //isInterrupted()方法继承自Thread类,判断线程是否被中断   
  88.                 Runnable task = null ;  
  89.                 try  {  
  90.                     task = getTask(id);     //取出任务   
  91.                 }catch (InterruptedException ex) {  
  92.                     ex.printStackTrace();  
  93.                 }  
  94.                 //如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程   
  95.                 if (task ==  nullreturn ;  
  96.                   
  97.                 try  {  
  98.                     task.run();  //运行任务   
  99.                 }catch (Throwable t) {  
  100.                     t.printStackTrace();  
  101.                 }  
  102.             }//  end while   
  103.         }//  end run   
  104.     }// end workThread   
  105. }  

 

2.测试类

 

Java代码   收藏代码
  1. package  com.tdt.test;  
  2.   
  3. import  com.tdt.impl.ls.ThreadPool;  
  4.   
  5. public   class  ThreadPoolTest {  
  6.       
  7.     public   static   void  main(String[] args)  throws  InterruptedException {  
  8.         ThreadPool threadPool = new  ThreadPool( 3 );  //创建一个有个3工作线程的线程池   
  9.         Thread.sleep(500 );  //休眠500毫秒,以便让线程池中的工作线程全部运行   
  10.         //运行任务   
  11.         for  ( int  i =  0 ; i <= 5  ; i++) {  //创建6个任务   
  12.             threadPool.execute(createTask(i));  
  13.         }  
  14.         threadPool.waitFinish(); //等待所有任务执行完毕   
  15.         threadPool.closePool(); //关闭线程池   
  16.   
  17.     }  
  18.   
  19.     private   static  Runnable createTask( final   int  taskID) {  
  20.         return   new  Runnable() {  
  21.             public   void  run() {  
  22.             //  System.out.println("Task" + taskID + "开始");   
  23.                 System.out.println("Hello world" );  
  24.             //  System.out.println("Task" + taskID + "结束");   
  25.             }  
  26.         };  
  27.     }  
  28. }  

 

 

结果:

Java代码   收藏代码
  1. 工作线程 0 等待任务...  
  2. 工作线程1 等待任务...  
  3. 工作线程2 等待任务...  
  4.   
  5. 工作线程0 开始执行任务...  
  6. Hello world  
  7. 工作线程0 等待任务...  
  8.   
  9. 工作线程1 开始执行任务...  
  10. Hello world  
  11. 工作线程1 等待任务...  
  12.   
  13. 工作线程2 开始执行任务...  
  14. Hello world  
  15. 工作线程2 等待任务...  
  16.   
  17. 工作线程0 开始执行任务...  
  18. Hello world  
  19. 工作线程0 等待任务...  
  20.   
  21. 工作线程1 开始执行任务...  
  22. Hello world  
  23. 工作线程1 等待任务...  
  24.   
  25. 工作线程2 开始执行任务...  
  26. Hello world  
  27. 工作线程2 等待任务...  

 

 

 

评论
18 楼 sunnylocus 2011-09-06   引用
koone 写道
大概看明白了:这个就是生产消费模式吧,使用一个工作线程池和一个任务现场队列来完成的。不过没太明白,当加入了任务线程时是怎么样通知工作线程来工作的

此时的工作线程执行wait()方法后阻塞了,使用notify()方法通知工作线程干活
17 楼 koone 2011-09-04   引用
大概看明白了:这个就是生产消费模式吧,使用一个工作线程池和一个任务现场队列来完成的。不过没太明白,当加入了任务线程时是怎么样通知工作线程来工作的
16 楼 sunnylocus 2011-02-25   引用
wanghonghui023 写道
楼主有点像八一队的中锋-德嘞黑啊!

因为我长的黑,他们都说我是非洲人
15 楼 wanghonghui023 2011-02-25   引用
楼主有点像八一队的中锋-德嘞黑啊!
14 楼 sunnylocus 2010-05-13   引用
zerxd 写道
mht19840918 写道
又一轮子~

在1.5之后,是有更好的解决方案。不过在1.4这之前,这会是一个好的方法。

说的对!
13 楼 zerxd 2010-05-12   引用
mht19840918 写道
又一轮子~

在1.5之后,是有更好的解决方案。不过在1.4这之前,这会是一个好的方法。
12 楼 qn_lf 2010-04-30   引用
正好在找线程池  不过以前并发都考虑  SwingWorker模式
11 楼 mht19840918 2010-04-01   引用
又一轮子~
10 楼 haiya 2010-01-27   引用
getTask()那里等待我知道,问题是如果队列不是0呢?
不过很奇怪,我试了改了下那个createTask,里面的线程输出hello以后sleep5秒,然后试到它确实会等待前一个任务完成再去取新任务,不过我又不知道是哪里起的作用。
如下,System.out.println("Task running...");会在sleep完以后再输出

public void run() {
while(! isInterrupted()) {  //isInterrupted()方法继承自Thread类,判断线程是否被中断
Runnable task = null;
try {
task = getTask(id); //取出任务
}catch(InterruptedException ex) {
ex.printStackTrace();
}
//如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程
if(task == null) return;

try {
task.run();  //运行任务
System.out.println("Task running...");
}catch(Throwable t) {
t.printStackTrace();
}
}//  end while
}//  end run
9 楼 sunnylocus 2010-01-27   引用
haiya 写道
我看你这段代码就是取了任务,让它自己去执行,然后自己又继续去取下一个任务,哪里有等待呢?
记得好像Effective Java的作者说过不推荐用ThreadGroup,说是实现不是太好。

while(! isInterrupted()) {  //isInterrupted()方法继承自Thread类,判断线程是否被中断  
                Runnable task = null;  
                try {  
                    task = getTask(id);     //取出任务  
                }catch(InterruptedException ex) {  
                    ex.printStackTrace();  
                }  
                //如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程  
                if(task == null) return;  
                  
                try {  
                    task.run();  //运行任务  
                }catch(Throwable t) {  
                    t.printStackTrace();  
                }  
            }//  end while

看仔细些,取任务的时候用通过getTask()方法获取的,getTask()方法是从队列中取出一个任务,如果队列等于0,则调用 wait()方法将自身线程挂起。因为我以前用的jdk1.4,没有现成线程池就写了个,如果你用jdk1.5及以上版本就不用自己写了,因为都有现成的 线程池
8 楼 haiya 2010-01-27   引用
我看你这段代码就是取了任务,让它自己去执行,然后自己又继续去取下一个任务,哪里有等待呢?
记得好像Effective Java的作者说过不推荐用ThreadGroup,说是实现不是太好。

while(! isInterrupted()) {  //isInterrupted()方法继承自Thread类,判断线程是否被中断  
                Runnable task = null;  
                try {  
                    task = getTask(id);     //取出任务  
                }catch(InterruptedException ex) {  
                    ex.printStackTrace();  
                }  
                //如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程  
                if(task == null) return;  
                  
                try {  
                    task.run();  //运行任务  
                }catch(Throwable t) {  
                    t.printStackTrace();  
                }  
            }//  end while
7 楼 sunnylocus 2010-01-27   引用
haiya 写道
工作线程会等待自己取得的任务完成以后再去取新的任务吗?

当然可以了,其实这就是经典的生产-消费者模式。如果队列里没有任务,消费线程会挂起,如果生产线程向队列加入新任务,生产线程会唤醒挂起的消费线程去队列中取任务。jdk1.5以后的版本有ThreadPoolExecutor线程池,可以直接拿来用
6 楼 haiya 2010-01-27   引用
工作线程会等待自己取得的任务完成以后再去取新的任务吗?
5 楼 sunnylocus 2010-01-14   引用
echozhjun 写道
不好意思,是可以的。敲错了代码

没关系,刚才我还纳闷代码我都测试过没问题,我以为与系统有关呢。
4 楼 echozhjun 2010-01-14   引用
不好意思,是可以的。敲错了代码
3 楼 echozhjun 2010-01-14   引用
我试了下你的程序,貌似不能closePool呀?
2 楼 sunnylocus 2009-11-02   引用
only_java 写道
可以自动或手动设置线程数量,么体现出来啊?

自动设置线程数量,可以根据CPU的数量来设定
int singleCPUcount =5
int totalThreadcount = Runtime.getRuntime().availableProcessors() * singleCPUcount
ThreadPool threadPool = new ThreadPool(totalThreadcount );
1 楼 only_java 2009-10-12   引用
可以自动或手动设置线程数量,么体现出来啊?
发表评论
表情图标

字体颜色:  字体大小:  对齐:
提示:选择您需要装饰的文字, 按上列按钮即可添加上相应的标签

(快捷键 Alt+S / Ctrl+Enter)

sunnylocus
搜索本博客
我的相册
我的留言簿 >>更多留言
  • 您好,请问一下为什么在每次发完短信之后都会报一下的异常: java.net.So ...
    -- by jiangzhou556
  • 您好!能不能加一下QQ(316171399)有几个关于联通短信网关的问题问你一下
    -- by jiangzhou556
  • 刚刚加你QQ 和msn了,请加下我呗,想了解一下sgip接收这块,非常感谢
    -- by yjpwy
存档
  • Rss
  • Rss_google

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值