请教一个关于线程的问题

正在完成一个Web应用的架构设计,基本的思路是采用Struts + Spring,

由于此Web应用程序的外部接口是大量调用Web Service服务接口,而且服

务端提供的并发数量支持有限制,有些耗时也比较长,所以我考虑使用线

程来完成调用查询的工作。为了控制和管理线程的执行,我考虑使用

DL的util.concurrent包中的PoolExecutor来实现对于线程池及其管理。

但目前出现这样一个疑问,用户在请求时通过Action来调用javabean,

然后由javabean来调用PoolExecutor来装载相关的查询线程,例如叫做

QueryThread,但我希望QueryThread返回的结果能够返回给相应用户的

界面,如何保证返回结果对应用户界面,如何得到线程返回的结果呢?

哈哈 你走错方向啦,Web应用其实就是一个多线程应用,你写的Struts的Action和Jsp最后是以线程运行的,concurrent等包其实是Tomcat等Web容器都使用了。

你可以使用Borland的Optimizeit跟踪你的struts+Spring系统,会发现那些线程正在运行的。

哈哈,你没看过我写的书,不经常来Jdon,就会犯这些方向性错误。

你的并发问题不是向下向底部寻找解决方案,而是从性能架构设计等方面考量,从缓存以及Pool等处考量,虽然你使用了超强的Spring框架,但是不知道为什么要用它,这是很多人的问题啊。

使用Spring的Pool和Cache拦截器为你的应用提升性能吧。

直接使用线程性能提高不了哪里,Web应用的路线图:
线程 --> 容器的一些类 -->你的Web程序,你直接使用线程,只不过简去了容器的一些类,效果不明显,但是坏处明显:引来了多线程并发控制和死锁等可能。

为什么要有Web技术,就是怕大家都来使用多线程,线程编程是危险的。

多谢banq的指点,不过现在我如果不考虑Spring和Struts组和,而是单独采用Struts作为WEB开发框架,是否有使用concurrent的必要呢?

其实我使用线程池是为了异步的处理在WEB访问时调用Web Service
接口和返回,同时对调用的请求进行控制。如果不使用类似的线程池,还有什么替代的方式解决呢?

整个J2EE架构已经屏蔽了线程这样的微观结构,所以以前C/C++那些注重微观技术的思维在J2EE中要被架构框架替代。

你可以使用JMS这样的异步框架实现你的异步处理。

>而是单独采用Struts作为WEB开发框架,是否有使用concurrent的必要呢?

使用Struts其实就是使用Servlet技术,Servlet本身是一个多线程,当你有多个Action访问同一个对象时,需要考虑并发,但是在J2EE中,一般这样的对象都是组件对象,而组件对象要么是使用new,每次重新创建一个新的;要么使用object pool让一个线程独占一个对象,也就不存在并发问题。

当然,这有一个前提,你勿使用单态模式设计实现你的组件业务层,否则你必须又面临令人头疼的并发了。

在J2EE中将并发延迟到数据库,靠数据库的事务机制处理并发,这是一个很稳妥的方法。

还是有几个问题没有明白,还想打破砂锅问到底。

1.struts中的Action对象应该是singleton的吧,这样的实现是否会造成访问调用的并发瓶颈呢?
2.如果采用struts+spring这种框架,可以允许spring代理“偷偷地”创建多个Action对象,这样是否可以解决上述的问题呢?

其实我的应用一部分需要访问本地数据库,而大部分需要访问其他地点提供的Web Service服务。所以我提出要控制并发的理由是想解决这种远程访问的。目前这个服务提供者并没有提供可靠的并发支持数值,我想通过某种方式对这种并发访问的请求进行控制,所以才想到线程池这种思路。可能不是非常合适,不知是否有更好地解决方案呢?

MAJIAN的应用场景好像很适合用 多线程 啊~~

J2EE 在容器环境里要进行异步处理有三种风格:

1。多线程。这是一种有效但是违反 J2EE 规范的作法。J2EE 规范规定在容器环境内用户模式的代码不能使用多线程 API,比如创建THREAD等等。但是很多现存应用就是这么做的,包括一些世界顶尖的 J2EE 产品。
这个作法的危险在于,容器内的线程往往带有很多容器的缓存,比如THREADLOCAL存储结构。用户代码如果自己创建线程,很多容器内的数据会被继承到用户线程里,最终造成内存泄漏。这种内存泄漏,有时会是灾难性的,因为容器线程缓存的数据可能非常宏观,比如CLASSLOADER。

2。用JMS/MDB。这个办法符合规范,但是比较麻烦。

3。用 WorkManager。 WorkManager 是BEA/IBM共同推出的一个JSR,现在尚未正式成为J2EE规范,但是在最近的 WEBLOGIC/WEBSPHERE 内已经有支持。这是最简洁,最规范的一个办法。

至于异步处理的结果如何返回用户界面,这可以采取 Producer/Consumer 模式。虽然异步处理内部是并行处理的,但是外部用户界面(JSP/SERVLET/SESSIONBEAN)看到的那个界面可以封装为同步的BLOCKING界面。

另外,ACTION为什么不会引起瓶颈的原因,和SERVLET一样。SERVLET、JSP也是SINGLETON,它们不是也不会有瓶颈问题吗?当然,除非你的SERVLET有INSTANCE MEMBER。

如果你决定不使用,或者你的容器不支持 WORKMANAGER (虽然我强烈推荐你用它),那么我建议你用多线程。

不过要注意,如果你用某个开源的库,要多调查一下,这个库的 THREAD 在创建是是否清除了可继承对象,比如 THREADLOCAL, ACCESSCONTROL, 等等。

如果你决定直接用简单的 NEW THREAD。那么建议你建立自己的THREAD子类,在构造函数里积极清除上述成员。

SPRING 框架对这种模式的异步处理并没有有效途径。

>struts中的Action对象应该是singleton的吧,这样的实现是否会造成访问调用的并发瓶颈呢?

Action的方法execute相当于线程的run方法,这样一说,你应该明白如何处理Action了,你使用Web架构实际是在使用多线程,一般应用无需我们注意这个秘密机制,但是象你这样特殊应用,就必须搞明白了。

>果采用struts+spring这种框架,可以允许spring代理“偷偷地”创建多个Action对象,这样是否可以解决上述的问题呢?

你对组件概念和设计模式等概念需要补课一下,使用Spring加观察者模式可以实现你的异步机制,TSS最新文章如下:
http://www.theserverside.com/articles/article.tss?l=SpringLoadedObserverPattern

我也看到Spring下的一个JMS产品,忘记网址了,你要查一下。

>其实我的应用一部分需要访问本地数据库,而大部分需要访问其他地点提供的Web Service服务。所以我提出要控制并发的理由是想解决这种远程访问的

远程访问是需要异步机制的,例如邮件发送等,因为远程连接过程不知道会发生什么问题,中断停滞都可能发生,如果你采取线程,一个线程可能莫名其妙的死在那里,你无法干涉,线程编程最大缺点就是我们无法干预运行中的线程,除非你使用汇编。

那种习惯使用底层机制,其实还是使用传统编程C/C++等思维来看待java,或者对Java代表的模式或架构这些熟视无睹,甚至认为这些不是科学的东西,我觉得他们更喜欢用汇编,可惜我也是从汇编8031过来的,我已经彻底告别那种石器时代。

以前看到程序员杂志,一位顶尖台湾作者分析java Collection的字节码,机器码十进制都分析透彻,他以为这样就能让初学者掌握Collection,实际是更大的方向误导,我一直强调,搞java要有向上思维,自己的研究方向要向上拔,这个观点两年前我就一直在说。

可惜很多经验丰富的人不原意对自己发出挑战,改变自己,那么软件业只有淘汰他了。


呵呵,老板的那个链接只是关于如何用 SPRING 配置实现一个 PUB/SUB ,或者说 OBSERVER/OBSERVABLE 模式,并不是关于并行异步处理吗,压根没有提到怎么实现异步机制啊~~

“底层机制,C/C++思维”什么的,如果是指多线程那可很不确切。难道多线程不是 JAVA 的强项?事情很简单,对于“并行任务”, Spring 没有能力解决(当然这也不是 SPRING 的设计用途)。如果担心使用多线程会导致“线程可能莫名其妙地死在那里”,那么根本不应该用 JAVA,干脆写 PHP 得了。:-)

我也不中意在 J2EE 用户模式代码里用多线程,可是在现行 J2EE 规范下,这是有些问题(J2EE1.4之前的定时器问题,JSR 237之前的并行任务问题)的唯一选择,很多产品,比如 大名鼎鼎的Quartz Scheduler,甚至 WEBLOGIC/WEBSPHERE 的一些增值产品,都是这么做的。

JMS/MDB 虽然可行并且符合规范,但是太重量级了,因为它至少要求 JMS PROVIDER 和 MDB 容器,这已经远远超出了楼主的原 MTR (TOMCAT + SPRING)。并且,如果你仔细考虑就会意识到:即使你用了 JMS 方案,最终也要用线程API来实现 PUB/SUB 模式。 如果采用JMS的本意是为了避免在J2EE环境中使用多线程,那么JMS并救不了你。 :-)

如果你用某个第三方框架来隐藏 PUB/SUB,呵呵,那才叫“掩耳盗铃”。框架,比如 SPRING,也运行在用户模式里,它替你违反规范,还不如干脆自己干来得坦荡放心。SPRING 的内存泄漏很出名的呕,不信GOOGLE下试试~~ 病根就在它的线程机制上。

也正是因为这个多线程和JMS的二难问题,才诞生了 WORKMANAGER 的 JSR。无论老板喜欢不喜欢,很快要进入规范了。事实上,WEBLOGIC/WEBSPHERE内部已经进行了大规模的运用,曾经以用户模式多线程方式设计的很多问题都已经或者正在向 WORKMANAGER 移植。老板要是不即时挑战自己赶快补课,被淘汰起来那才叫快~~开玩笑啊,呵呵。

工具,模式,框架,包括SPRING,WORKMANAGER,甚至 JAVA EE 规范,甚至 JAVA 语言,在一个程序员的职业生涯中,不过是正常的技术更新周期而已,相当于运输卡车司机每两年就要换卡车。说这些东西是“挑战”,颇有点神经兮兮的,贻笑大方了。缺乏扎实的功底,有再多“模式”“框架”的点缀,也终归是花拳绣腿,不堪重任。

李开复大侠建议大家要苦练基本功而不要过多追求那些时髦的工具,信矣。

两位大侠怎么开始讨论起那个叫“春”的项目来了阿,严重跑题,呵呵。

框架是否优秀要看它在具体环境和项目中的表现拉,我还是比较关心我

提出的问题本身,我觉得是一种非常常见的问题,但不知道应该采用什么

方法比较合适。具体场景是这样的:

1.核心业务系统对外业务(办理)访问接口都是通过Web Service或者远程
EJB对象提供的,核心业务系统本身具备多个客户端,包括浏览器和Java
GUI客户端,并且均使用这个接口访问后台服务;
2.准备建设的这个新系统是采用浏览器方式的应用,也是通过这类接口完
成业务办理,使用该新系统的业务并发量很高,峰值达到每日2000人
次,每人次操作调用超过20。
3.为了降低对核心业务系统的压力,我需要考虑对“调用访问接口”这个
层次进行控制。基本的思路是可以控制调用访问接口的并发数,对超出
这个并发数的用户作出友好提示,说明系统繁忙,等待稍候进行处理。
当然这种思路在业务上也是被认可接受的,也就是说允许这种类型的等
待。尽量不能出现由于用户并发请求过多而引起核心系统瘫痪的情况
出现。

对于这样的一种要求,应该在技术方案上如何考量呢?或者说思路怎样呢?

同时接受不使用Java语言的解决方案。

谢谢大侠指导阿。

在下不过三脚猫的功夫,好发言也多半出自自我表现,虽然也有助人为乐的成分,但是妄称大侠是万万不敢的。

在没有更多数值数据的情况下,我对你的需求总结如下:

1。从客户端视角看,系统响应方式是同步的。--这一条是必须的么?因为这一条对整体架构影响很大。如果这条可以放松,也就是说客户端可以接受某种异步响应方式,那么整体架构选择就灵活很多。放松这一条可能带来系统整体性能(主要是throughput方面)的巨大效益。下面的讨论将假设这一条不能改变,必须是同步的。

2。从实现视角看,后台业务系统(J2EE 属于叫企业信息系统)是远程,多源的。

3。事务是查询性质,还是交易性质?不详。

4。是否有事务处理需求?不详。

5。数据源(后台业务系统)是否支持 XA?不详。假设远程EJB支持,而WS不支持。

6。对后台业务系统的访问结果,是简单汇总,还是有复杂逻辑流程?不详。

在上述这些假设下,我的基本设计空间是:

1。客户端界面:
方案A:同步语义的 WEB SERVICE 界面。
优点:支持远程,支持多种客户端,包括.NET客户端,甚至OFFICE客户端。SOA友好。对网络传输层要求低,方便跨越防火墙。
缺点: WEB SERVICES 性能相对较低,对事务处理的支持(WS-BA, WS-AT)因平台而易。

方案B:SESSION BEAN。
优点:支持远程,支持JAVA和WEB客户端。支持事务交易和安全需要。标准相对稳定。平台支持较完善。性能相对于WS较好。可以在EJB基础上再次封装为WS界面。
缺点:不能跨越防火墙。不能支持.NET客户端。

2。并行实现方案:

方案A:BPEL。
优点:标准。对基于 EJB 和 WS 的后端系统都有良好的支持。支持XA事务(如果后端系统本身支持),与其他 WS-* 标准兼容性良好。SOA友好。支持并行。支持复杂逻辑流程。BPEL 对客户端已经体现为 WS 服务。
缺点:平台选择有限。只有 ORACLE 或者 WEBSPHERE。

方案B: WEBLOGIC INTEGRATION
优点:工具支持完善。如果你已经使用WEBLOGIC,那么这个选择很自然。
缺点:不基于BPEL标准。

方案C: 多线程实现。每个线程并行访问后端系统,结果以 PUB/SUB 模式汇总给客户端。

优点:性能优良,封装灵活。平台层次减少,MTR非常低,平台选择范围宽广,自己拥有全部代码。无需EJB容器,无需 WS 容器。 方便封装为EJB或者WS。
缺点:不够“书面规范”。比起上述两个方案要写更多代码,开发周期较长。

方案D: WORK MANAGER。WORK MANAGER 的界面是 LISTENER 风格,结果汇总很方便。

优点:符合规范。性能优良,封装灵活。外部界面可以封装为EJB或者WS。开发风险小。
缺点:需要容器支持。平台选择限于 WEBLOGIC、WEBSPHERE。

方案E: JMS/MDB 实现。

每个后端系统需要配置一个请求QUEUE,所有后端系统结果响应返回到一个响应TOPIC/QUEUE(取决于响应是否可能在多个客户端间共享)。结果 MDB 汇总中间结果,通知客户线程提取最终结果。

优点:规范。性能较好,尤其有良好的横向伸缩性。外部封装灵活。支持安全性和事务考虑。
缺点:配置繁琐,不适合“套装软件”开发。各平台对 JMS 的支持差异非常大,实践中 JMS 实现的可靠性有时不尽人意。需要对所选平台的 JMS 做广泛详细的预研和试验。

方案F: ASP.NET + BIZTALK。你自己说的不限于JAVA。呵呵。

其实MaJian这个方案很普通,主要特别的就是这句:
"尽量不能出现由于用户并发请求过多而引起核心系统瘫痪的情况"

而解决并发访问最具有伸缩性的是JMS,JMS的前台服务器只是管理维护用户的TCP连接,不做任何业务处理,这样,将有限的CPU全部集中在维持用户连接上,保证用户不至于不能连接上服务器,如果一台不够,可实现多台,JMS分布式集群特点非常不错,在国外大型股票交易系统中都有成熟应用,在google搜索一下有很多成熟个案、

PUB/SUB是异步系统的一种形式,观察者模式以及Spring AOP这方面早就有很多研究文章,如何使用AOP优雅实现观察者模式,有人洋洋万言一把,竟然这些基本设计概念都不清楚。Spring 的JMS是一种轻量的解决方案,除了上面的TSS文章,这篇文章也可供参考:
http://www-128.ibm.com/developerworks/cn/java/wa-spring4/

未来Java设计必然走向框架为王之路,那种依赖工业厂商平台的欺骗之路早就应该终结,我们总是等待JSR出那个规范出那个标准,自从Spring之类这样优秀框架出台以后,我们不能再被SUN同伙牵着鼻子走了。

对于程序员,更多应该从设计角度来看问题,以公允公平的模式来研究系统,而不是以具体厂商产品来谈解决方案,那不是成了厂商的代言人,为他们做广告了?

就李开复那种沽名钓誉的人只能骗骗纯情的大学生,上次在中央电视台做节目没让他灰溜溜下台已经不错了。

在Spring 1.2.1的JPetstore中的applicationContext.xml有关发送Email的配置,这其实相当于另起一个线程发送Email,因为Email发送是个外部网络连接,时间不确定的。


<!-- Advisor encapsulating email advice -->
<!--
<bean id="emailAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<constructor-arg><ref local=
"emailAdvice"/></constructor-arg>
<property name=
"pattern"><value>.*insertOrder.*</value></property>
</bean>
-->

这里设置了一个观察点,在insertOrder方法激活时,激活emailAdvice



<bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
<property name=
"mailSender"><ref local="mailSender"/></property>
</bean>

<bean id=
"mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name=
"host"><value>${mail.host}</value></property>
</bean>

emailAdvice使用MailSender连接SMTP服务器发送邮件,这一系列动作是在insetOrder这个主要业务操作时同时发生,而insertOrder方法体内执行完毕是不等待Email是否发送完成的,这是异步机制,很类似你说的在一个线程里再抛出另外一个线程吧。

以上只是使用了Spring的AOP实现的观察者模式,还没用到JMS呢。你先弄起来跑吧。

呵呵,

老板既然把 IBM 那篇文章找出来,自己就应该先看看懂再忙着给别人推荐。这篇文章只介绍了如何用SPRING配置 JMSSender/JMSReceiver,并没有任何涉及“异步、并行处理”的内容。

这么说吧,老板给说说JMSReceiver.processMessage()是谁来调用的?在那个线程里?为什么说是并行的?文章本身可说了,这个方式是“同步提取”的呕~~

就是你不看英文,也该看看代码,和代码是怎么运行的。那个JMSReceiver 是单独在一个Standalone 的 ANT session 里跑的呕~~~

其实,那么费劲GOOGLE出一篇IBM的文章干吗? SPRING 自己的 JMS 文档(第18章)写得很清楚:SPRING 现在只集中在消息发送端功能,未来才会加入“异步”消息接受功能。并且,同一章节后面(18.4.2)又提到,SPRING 里现在支持的那个“同步”消息接受功能(也就是老板推荐的那篇IBM文章),是一个危险的作法。

也就是说,老板给大家推荐的,是他自己没看懂,SPRING 本身也不推荐的“危险”作法。

“开源框架”的积极支持者,“JAVA大侠”,居然对SPRING的基本常识还不如我这个SPRING的批判者,JAVA的怀疑者,呵呵~~~

老板别放弃,我积极鼓励你继续GOOGLE,看你能不能找出一篇,哪怕一篇,只要一篇,介绍SPRING怎么做异步并行处理的文章。我拭目以待。

至少在 JMS 的良好伸缩性上,还是能达到共识的。不容易啊~~

JMS 的问题在于JMS PROVIDER平台和配置差异非常大,要实现良好的性能往往需要对平台有足够的经验。我当然了解 JMS 有很多大型的部署。但是,我也了解,有一些公司,甚至是世界顶尖的商业软件公司,在 JMS/MDB 开发方面吃了大苦头。当然,最终支付了IBM无数的咨询费之后,问题是解决了。可是对于很多中国公司而言,在上JMS之前,你需要仔细调研一下你对所采用的JMS PROVIDER是不是有足够的经验,是不是有足够的咨询费预算。毕竟,不是人人都向美国金融机构那样财大气粗,所以用“国外大型股票交易系统”作例子并没什么说服力。人家股票交易商还坐直升机上班呢,你也来一驾?

并且,欧美的金融业,制药业,和其他一些大公司,政府部门等等,对所采用的软件有严格的法律,外部和内部审计规定,标准。这些审计过程是非常严格和耗费时间的。WEBSPHERE/WEBLOGIC 也是近几年才被接纳为核心业务软件平台。象 SPRING, HIBERNATE, JBOSS 这样的开源软件,不是说它们技术不好,但是它们根本没有可能在大型股票交易系统里被采用。所以即便某某银行使用了IBM WEBSPHERE MQ的JMS PROVIDER,出于法律原因也绝对不可能用 SPRING 作为 JMS 的封装。

说 SPRING 的 JMS 是一种轻量级的解决方案,倒也无可厚非。因为 SPRING 在 JMS 方面根本也没有什么作为。问题在于,无论 SPRING 本身如何“轻量级”,JMS 就是一个重量级的东西。

再者,如果你有预算买了 WEBSPHERE MQ,却放着 WEBSPHERE 的 MDB 不用,非要用SPRING,那才叫有病。从这一点看,SPRING 框架集中做消息发送,而不过多花费精力做消息接受从而与 MDB 竞争,是明智的选择。大概只有老板这样的“框架”圣战主义者才可能做出如此怪异的框架方案选择。

不知道老板从哪里看出我不清楚“基本设计概念”。倒是你自己,人家明明问一个“并行”的问题,你却给了各 PUB/SUB 的 spring 配置作答案。 经常给别人推销SPRING,原来对SPRING的了解,至少在JMS方面,居然有小儿科式的“基本概念”错误。成天“模式”不离口,竟然以为“PUB/SUB是异步系统的一种形式”。真正笑话连篇~~

“PUB/SUB”模式本身只设计互相写作的组件如何协调状态,至于协调的手段是异步还是同步,是并行还是串行,并不是PUB/SUB的内容。当然,所谓“设计模式”界乱用术语的现象司空见惯。有些术语,模式根本没有公认严格定义,姑且就不算老板的问题了吧。

我给楼主的建议,自己数数至少包括WEBLOGIC/WEBSPHERE/ORACLE三个平台,多种实现方案,甚至包括BIZTALK(当然玩笑的成分居多,不过用BIZTALK的确是可行的)。老板说说我是给哪家做广告的?

倒是老板,明明 SPRING 文档自己都承认不灵,“危险”(SPRING文档原词)的 JMS 同步消息接收功能,你非要无中生有地说那是个异步解决方案推销给别人,另一方面却对成熟而具备强大JMS/MDB功能的产品视若无睹,不以产品性能论高下,对 SPRING 其实不甚了了却无原则地追捧,倾向性一目了然,才真正是不知出于什么目的,什么日程,什么心理。

李开复是什么人在计算机界做了何等贡献,看来你根本毫无概念,否则也不会说这么无知的话。孔子在某些人看来,也是很灰溜溜的沽名钓誉之徒。可惜那某些人,现在只是作为笑话才被人记得。

又洋洋万言了。

本人在本楼的头篇发言,不过是对楼主的问题有感而发,回观全文,毫无针对任何人的字眼,完全就事论事。倒是老板一出口,便是“不愿挑战自己啊,被淘汰啊”云云一些毫无意义的话,完全不是一个成年人的修为,惶论什么“大侠”?

我也知道老板是吃咨询饭的,需要一个颜面信用,所以本人几个月前最初在宝地的发言,是出于维护老板的。后来在关于集群的讨论中再次发现老板的基础知识薄弱,错误概念连篇,也就是点到而止。

但是一个人在IT界以技术立足,需要用真实的功底来建立自己的信用,名望。用自己的口水靠无原则无根据地贬低别人,最多把自己塑造成一个丁春秋的形象。