锁定老帖子 主题:线程池示例代码,请大家多指教
精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (13)
|
|
---|---|
作者 | 正文 |
发表时间:2009-08-19
LZ的容器放置的是所有的Thread对象,给每个Thread对象一个状态,在getIdleThread()的时候通过遍历Thread的状态来决定是给空闲对象还是等待,这样其实不好。common pool是这样设计的:容器中只保存空闲对象。这样只要判断容器的size就可以知道是否有空闲对象了,当然common pool是不等待的,它在判断如果没有空闲对象的话就直接调用factory的makeObject方法new出一个新对象。LZ可以自己加上wait处理。获得对象后容器remove()该对象。
在return的时候,就直接把对象add()容器中,这样是不是更简单呢 哈哈 |
|
返回顶楼 | |
发表时间:2009-08-19
xujunJ2EE 写道 LZ的容器放置的是所有的Thread对象,给每个Thread对象一个状态,在getIdleThread()的时候通过遍历Thread的状态来决定是给空闲对象还是等待,这样其实不好。common pool是这样设计的:容器中只保存空闲对象。这样只要判断容器的size就可以知道是否有空闲对象了,当然common pool是不等待的,它在判断如果没有空闲对象的话就直接调用factory的makeObject方法new出一个新对象。LZ可以自己加上wait处理。获得对象后容器remove()该对象。
在return的时候,就直接把对象add()容器中,这样是不是更简单呢 哈哈 1,同意,我感觉pool最原初的设计就应该是这样,它应该不涉及到业务逻辑或者说对象属性,borrow的时候返回的是一个原始的对象,只是这个对象早已经被构造了. 在returnObject()和borrowObject()的时候 应该事先对 对象 进行一些处理或者说成员变量的修正. 2,如果status来标识actived or sleeping,我感觉是不是也有它的好处? |
|
返回顶楼 | |
发表时间:2009-08-19
to C-J:
要看你的status放置到什么地方了,如果你要求Pool中的对象都必须有status这个属性,那么对这些对象就只能侵入了。 或者你可以通过在Pool中放置一个proxy对象,该对象包含你的原始对象和status属性。 但总的来说,我还是感觉common pool的实现比较简单,在容器中直接放置空闲对象。我以前作对象池的思路也是类似自己维护状态,后来想想,其实有更简单的方式为什么不用呢 |
|
返回顶楼 | |
发表时间:2009-08-19
建议多看看jdk1.5及以上版本的多线程相关的东西,线程池在jdk1.5以后已经不推荐使用了。
|
|
返回顶楼 | |
发表时间:2009-08-19
wmj2003 写道 建议多看看jdk1.5及以上版本的多线程相关的东西,线程池在jdk1.5以后已经不推荐使用了。
不同意这种看法,线程池是死的但是怎么活用它学问就大了.同一个线程池可以用的很好也可以用的很垃圾. 几种经典的线程使用模型还是很有用的.怎么找可用线程,怎么返回线程,创建线程策略,线程和业务的无缝结合,通信等等内容够喝一壶的. |
|
返回顶楼 | |
发表时间:2009-08-19
最后修改:2009-08-19
同意fjlyxx观点,我们就是要探讨不同情况下的对应的最优的线程池模型
fjlyxx兄,看了你的代码有几个问题请教一下 1、代码池的最小空闲线程个数和最大空闲线程个数由什么来决定 2、代码池为什么没有监控请求的线程,而只有监测工作线程状态和优化工作线程个数的监控线程, 监控请求的线程也应该放在线程池中吧 希望大家可以分享自己研究的现有优秀框架和服务器的线程池方面的心得 到最后每个人都能写出一篇对线程池模型应用的总结 那就是我们结贴的时刻了 |
|
返回顶楼 | |
发表时间:2009-08-20
xujunJ2EE 写道 to C-J:
要看你的status放置到什么地方了,如果你要求Pool中的对象都必须有status这个属性,那么对这些对象就只能侵入了。 或者你可以通过在Pool中放置一个proxy对象,该对象包含你的原始对象和status属性。 但总的来说,我还是感觉common pool的实现比较简单,在容器中直接放置空闲对象。我以前作对象池的思路也是类似自己维护状态,后来想想,其实有更简单的方式为什么不用呢 对,我的意思也就是 status属性有必要么? 恰好我看到2个项目都这样做...所以会提出疑问.. |
|
返回顶楼 | |
发表时间:2009-08-20
我个人认为没有必要,象LZ那样的是专门的Thread对象的线程池,所以他可以自己定义一个workThread对象,但如果你是开发一个类似common pool这样的通用对象池,你根本不知道放入你池中的对象是什么,你怎么能让放入你pool中的对象都实现一个state的属性呢,一种方式就是要求放入你pool的对象都实现一个interface中的读写state方法,这样就侵入原始对象了。还有一种就是在pool中放入原始对象的proxy对象,在proxy中定义state。而且你还要考虑对象的activate(), passivate()等处理,否则你从pool中拿到的就是一个脏对象,一般来说我们放对象池的都是有状态对象,无状态对象完全可以用单例来作,没有必要pool化。
common pool很多的思想还是很优秀的,他通过一个factory来剥离这些操作,让你的原始对象完全无侵入,对于需要放入pool的对象,你实现一个factory,在factory中处理状态操作和对象产生,这样将这些可能导致侵入的方法都剥离了。 至于common pool没有实现wati(),我想这并不是一个bug,而且在某些情况下,这是一个很好的考虑,thread的等待往往可能要化更多的时间,这个时间可能比创建一个对象更多。所以,common pool的设计就是给你一个pool,pool里面都是可复用的对象,当你不够用的时候就创建新对象,够用的时候就用pool里面的对象。在rod的without EJB中也说过,对象pool有时候不是好事,当并发请求的线程小于pool的size,那么请求线程在堵塞,当pool比size大的时候,pool实际上有点浪费。所以spring默认都是单例。我觉得common pool在设计的时候可能想到了这个因素,当并发线程大于pool的时候,干脆就创建对象。 |
|
返回顶楼 | |
发表时间:2009-08-20
如果你的对象确实很重量级,确实需要限制对象数量,那么可以稍微修改一下common pool的代码,通过activeNum来判断活动对象数量,以下代码是我修改common pool的源码,已测试通过;
Object obj = null; //如果Pool中有对象就直接给付 if(pool.size()>0) { obj = pool.remove(0); System.out.println("线程直接获得对象"); } /* *如果Pool中没有对象,要区分两种情况: *1 没有到达最大对象数,继续创建一个新的对象 *2 到达对象最大数了,等待其他线程释放对象 */ else { //没有到达最大对象数,继续创建一个新的对象 if(activeNum < parameter.getMaxNum()) { obj = objFactory.makeObject(); System.out.println("线程new获得对象"); } else { try { System.out.println("线程在等待!"); this.wait(); } catch (InterruptedException ex) { throw new Exception("线程异常"); } obj = pool.firstElement(); System.out.println("线程等待结束,获得其他线程return的对象"); } } //对象的状态设置,并在任何发生异常的情况下钝化对象状态,取消引用 try { //设置该对象为活动状态 objFactory.activateObject(obj); //对象检验 if(!objFactory.validateObject(obj)) { throw new Exception("ValidateObject failed"); } activeNum ++; } catch(Throwable t) { objFactory.destroyObject(obj); obj = null; return obj; } return obj; } public synchronized void returnObject(Object obj) { //先钝化对象,清除状态 boolean passivate = false; try { if(objFactory.validateObject(obj)) { objFactory.passivateObject(obj); passivate = true; } } catch(Exception ex) { passivate = false; } //如果钝化成功,将对象放入到对象池中 if(passivate) { //如果对象池满了,直接销毁该对象 if(pool.size() >= parameter.getMaxNum()) { objFactory.destroyObject(obj); } else { pool.add(obj); } //通知wait notifyAll(); activeNum--; } |
|
返回顶楼 | |
发表时间:2009-08-20
最后修改:2009-08-20
xujunJ2EE 写道 我个人认为没有必要,象LZ那样的是专门的Thread对象的线程池,所以他可以自己定义一个workThread对象,但如果你是开发一个类似common pool这样的通用对象池,你根本不知道放入你池中的对象是什么,你怎么能让放入你pool中的对象都实现一个state的属性呢,一种方式就是要求放入你pool的对象都实现一个interface中的读写state方法,这样就侵入原始对象了。还有一种就是在pool中放入原始对象的proxy对象,在proxy中定义state。而且你还要考虑对象的activate(), passivate()等处理,否则你从pool中拿到的就是一个脏对象,一般来说我们放对象池的都是有状态对象,无状态对象完全可以用单例来作,没有必要pool化。
common pool很多的思想还是很优秀的,他通过一个factory来剥离这些操作,让你的原始对象完全无侵入,对于需要放入pool的对象,你实现一个factory,在factory中处理状态操作和对象产生,这样将这些可能导致侵入的方法都剥离了。 至于common pool没有实现wati(),我想这并不是一个bug,而且在某些情况下,这是一个很好的考虑,thread的等待往往可能要化更多的时间,这个时间可能比创建一个对象更多。所以,common pool的设计就是给你一个pool,pool里面都是可复用的对象,当你不够用的时候就创建新对象,够用的时候就用pool里面的对象。在rod的without EJB中也说过,对象pool有时候不是好事,当并发请求的线程小于pool的size,那么请求线程在堵塞,当pool比size大的时候,pool实际上有点浪费。所以spring默认都是单例。我觉得common pool在设计的时候可能想到了这个因素,当并发线程大于pool的时候,干脆就创建对象。 是的,你提到的大致4个问题: 1,commons pool中的StatckObjectPool 和 ReferenceObjectPool等 本身设计的确实不允许"脏"对象的,像你说的,外围的activate(), passivate()充当了"清理"工作.. 2, 引用 一般来说我们放对象池的都是有状态对象,无状态对象完全可以用单例来作,没有必要pool化。
真的是这样么? 既然对象有状态,还有必要用pool么? 我觉得这有点违背pool想法吧?且会混乱业务逻辑和抽象逻辑的,这点也是我现在比较迷惑的地方... 3,如果pool的_maxSleeping阀值设置不当的话,在多线程APP下确实会导致堵塞...上限阀值和下限阀值很重要吧... 4,另外commons提供了一个ReferenceObjectPool,这种的好处在于内存不足时,GC无条件回收pool中的空闲对象,.这样资源可适当得到利用..不过pool中总要有一定量的闲对象,不可能每次都new吧。 5,至于spring用单例的原因,我想是因为spring本身就是一个lightweight组件,Rob应该也很不喜欢weight.. 另外 我看到的commons中,是在borrow()时,如果pool中没有空闲obj的时候,就创建新的obj,当然这个新对象是无状态的,所以建立在pool存储也需要建立在"无状态对象"的基本之上... |
|
返回顶楼 | |