关于struts线程问题

我要自由
06-05-22 4 994

因为一些原因刚开始学java,用struts做项目,但是对java中的线程问题很困惑。。。希望有高手指点一二。。
我知道jsp和servlet本身是多线程的,线程安全问题主要是由实例变量造成的,所以一般避免使用实例变量,但是我不明白的是,如果在一个方法里new另一个类,而这个类中也存在实例变量,那这还是线程安全的吗??
比如在一个Action里调用一个DAO,如果这个DAO包含实例变量,这样是否安全。
不知道在使用struts框架的时候,需要注意些什么?特别是并发的时候稳定性问题。。。。。还有如何测试系统并发的稳定性呢????
谢谢了!!
这还是在这发的第一帖。。。。。。

banq
2006-06-06 11:03

J2EE应用程序最好保证:一个请求一个线程,一个业务对象,一个资源,就象专用通道一样。

不知你Dao中怎么会有单例变量的,一般同一个资源可以推给数据库,因为数据库有ACID机制,可以保证多线程操作的安全性。

我要自由
2006-06-14 23:37

Servlet是在多线程环境下的。即可能有多个请求发给一个servelt实例,每个请求是一个线程。
struts下的action也类似,同样在多线程环境下。可以参考struts user guide: http://struts.apache.org/struts-action/userGuide/building_controller.html 中的Action Class Design Guidelines一节: Write code for a multi-threaded environment - Our controller servlet creates only one instance of your Action class, and uses this one instance to service all requests. Thus, you need to write thread-safe Action classes. Follow the same guidelines you would use to write thread-safe Servlets.
译:为多线程环境编写代码。我们的controller servlet指挥创建你的Action 类的一个实例,用此实例来服务所有的请求。因此,你必须编写线程安全的Action类。遵循与写线程安全的servlet同样的方针。

1.什么是线程安全的代码
在多线程环境下能正确执行的代码就是线程安全的。
安全的意思是能正确执行,否则后果是程序执行错误,可能出现各种异常情况。

2.如何编写线程安全的代码
很多书籍里都详细讲解了如何这方面的问题,他们主要讲解的是如何同步线程对共享资源的使用的问题。主要是对synchronized关键字的各种用法,以及锁的概念。
Java1.5中也提供了如读写锁这类的工具类。这些都需要较高的技巧,而且相对难于调试。

但是,线程同步是不得以的方法,是比较复杂的,而且会带来性能的损失。等效的代码中,不需要同步在编写容易度和性能上会更好些。
我这里强调的是什么代码是始终为线程安全的、是不需要同步的。如下:
1)常量始终是线程安全的,因为只存在读操作。
2)对构造器的访问(new 操作)是线程安全的,因为每次都新建一个实例,不会访问共享的资源。
3)最重要的是:局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量。
struts user guide里有:
Only Use Local Variables - The most important principle that aids in thread-safe coding is to use only local variables, not instance variables , in your Action class.
译:只使用用局部变量。--编写线程安全的代码最重要的原则就是,在Action类中只使用局部变量,不使用实例变量。


总结:
在Java的Web服务器环境下开发,要注意线程安全的问题。最简单的实现方式就是在Servlet和Struts Action里不要使用类变量、实例变量,但可以使用类常量和实例常量。如果有这些变量,可以将它们转换为方法的参数传入,以消除它们。
注意一个容易混淆的地方:被Servlet或Action调用的类中(如值对象、领域模型类)中是否可以安全的使用实例变量?如果你在每次方法调用时
新建一个对象,再调用它们的方法,则不存在同步问题---因为它们不是多个线程共享的资源,只有共享的资源才需要同步---而Servlet和Action的实例对于多个线程是共享的。
换句话说,Servlet和Action的实例会被多个线程同时调用,而过了这一层,如果在你自己的代码中没有另外启动线程,且每次调用后续业务对象时都是先新建一个实例再调用,则都是线程安全的。

===========================================

以上是我找到令我自己满意的答案!!!
“2)对构造器的访问(new 操作)是线程安全的”
我想只有这一句话就够了!!

对了,我发现我不应该在这个版块发这个帖,还是很谢谢banq的回答!
谢谢!!!

banq
2006-06-15 17:37

非常全面,不错。

>对构造器的访问(new 操作)是线程安全的
>每次调用后续业务对象时都是先新建一个实例再调用,则都是线程安全的

这是正确的,这只是在Jsp+JavaBeans架构下适用。

通过new创建对象有很多设计问题,因此,实战中我们现在基本不通过new来获得对象。

既然不通过new获得对象,那么如何保证Struts线程问题?
原则就是:
一个请求一个线程,一个业务对象,一个资源,就象专用通道一样。
这里涉及对象多例、单例等复杂问题。



asklxf
2006-06-22 14:14

设计DAO最好设计成线程安全的,这样可以放心地注入到Action

如果DAO不是线程安全的,那也应该写一个Facade对前端提供线程安全的调用