1、Servlet的线程安全
Servlet规范定义,在默认情况下(Servlet不是在分布式的环境中部署),Servlet容器对声明的每一个Servlet,只创建一个实例。 如果有多个客户请求同时访问这个Servlet,Servlet容器采用多线程,Servlet容器维护了一个线程池来服务请求。线程池实际上是等待执行代码的一组线程,这些线程叫做工作者线程(Worker Thread)。Servlet容器使用一个调度这线程(Dispatcher Thread)来管理工作者线程。当容器接受到一个访问Servlet的请求,调度者线程从线程池中选取一个工作者线程,将请求传递给该线程,然后由这个线程执行Servlet的service()方法
当这个线程正在执行的时候,容器收到了另一个请求,调度者线程将从池中选取另一个线程来服务新的请求。要注意的是,Servlet容器并不关心这个第二个 请求是访问同一个Servlet还是另一个Servlet。因此,如果容器同时收到访问同一个Servlet的多个请求,那么这个Servlet的 service方法将在多个线程中并发的执行。
由 于Servlet容器采用了单实例多线程的方式(这是Servlet容器默认的行为),最大限度地减少了产生Servlet实例的开销,显著地提升了对请 求的响应时间。对于Tomcat,可以在server.xml文件中通过<Connector>元素设置线程池中线程的数目。
2、属性的线程安全
在Servlet中,可以访问保存在ServletContext,HttpSession和ServletRequest对象中的属性。
① ServletContext中保存的属性可以被所有的Servlet访问,所以不是线程安全的。
② HttpSession对象只能在处理属于同一个Session的请求的线程中被访问,我们可以认为在一个时刻只有一个用户请求,因此,Session对 象的属性访问是线程安全的。然而实际情况并非如此,用户可以打开多个同属于一个进程的浏览器(比如IE浏览器中点击新建,新的窗口属于同一个 session,同一个进程),多个线程可以同时访问到Session对象的属性
③ServletRequest只在一个线程中被访问。因为只有一个线程服务请求,所有请求对象的属性访问是线程安全的。要注意的 是,ServletRequest对象是作为参数传进service方法中的,这个方法结束后,若仍然保存请求对象的引用,请求对象的行为将是不可预料 的。(Servlet本身就是多线程的,如果再在其中创建线程,将导致执行情况变得复杂,容易出现很多线程安全问题,所以设计系统时尽量不要采用在 Servlet中创建进程的方法)
谈到线程安全问题,会有人建议在多线程环境中使用集合类对象时使用同步的集合类,例如用Vector代替ArrayList,用Hashtable代替HashMap,这里我将拷贝论坛中同行给出的解释加深自己对同步的理解
vector是线程安全的,就如同一个房间,房门上有把锁,锁只有一个钥匙,当很多人想进房间,拿到那把能开锁的钥匙(姑且叫做A)才可以进入房间,而等到A退出房间并将钥匙随便给到在房门口等待的其他一人(姑且叫做B)的手上,B才可以进入房间,这样能保证房间里的资源在同一时间只被一个人占用。
arrayList不是线程安全的,就如同一个房门上没有锁的房间,因而所有的人都可以同时进入房间,房间里的资源在同一时间被多个人占用。这样在多线程中会出现问题。比如说那个资源是马桶,多个人进去抢那一个马桶势必大大出手形成竞争(race condition)。这样说不准没有一个人能正常如厕,所以arrayList在多线程里面用的话会很危险。
反过来看楼主的说法,楼主用多个线程来查看vector,然后再往vector里面添加数据。
if(vector.size() == 0){
Thread.sleep(100);
vector.add(new Element());
}
我故意加了个Thread.sleep();
这样会存在什么问题呢,多个线程都会看到vector的空间等于0,然后往vector里面添加元素。就如同多个人看到房间里面的马桶一次都没有用过,于是都想用第一次,然后他们该怎么做呢?排队拿钥匙进入房间用马桶。于是马桶被用了3次。
而如果在这里是arrayList会是什么情况呢?所有的人都进去用,有可能马桶只被用了1次(arrayList里面只存用一个元素)。那为什么明明3个人用过马桶,最后却只被用了一次呢,这个与试试矛盾啊,这就是因为房门没有锁,3个人有可能同时共用了一次马桶,这个与事实想违背,所以说arrayList是不安全的。
那么楼主说vector也是不安全的 因为上面的一段代码,这段代码就好比是房间(1)外面有一个更大的房间(2),房间(2)的房门没有锁,所以所有的人都可以进入房间(2)来看,这样房间(2)是不安全的,不安全的原因是楼主没把房间上锁,但是房间(2)不安全并不代表房间(1)不是安全的。
总而言之,要想做到真正的线程安全,还是需要程序员根据具体问题在应用层设计自己的解决方案,而不能单纯的依靠某些提供的“同步”Java类