servlet多线程

1.我在网上看说  如果servlet实现了SingthreadModel接口 就能单线程执行,顺序执行。但是又有人说即便实现了这个借口也不能保证线程安全。
到底是怎么样呢?了解的朋友说说看法。
2.我看有的程序再用到某些变量的时候需要使用同步块包围起来。但是我不明白的是  到底什么样的类,什么变量 再用的时候需要使用同步块

就比如 一个doGet()方法里。我取一个session里的值。取出来后,假如取出的是个集合list,我想给list追加东西。。我看的那个程序,就把list用同步块锁起来,然后在这个区域内 追加元素。。我不明白为什么这里要包围,虽然我知道 因为假设有100万个人同时访问这一个变量就会出问题。但是我不懂了,每个用户的请求一来进入doget方法,都从里面去获取那个list,各自获取各自的啊。为什么就说他不安全了呢??!!
 
 
1.javax.servlet.SingleThreadModel接口是一个标识接口,如果一个Servlet类实现了这个接口,那么Servlet容器将保证在同一个时刻只有一个线程可以在给定的servlet实例的service方法中执行。而将其他所有请求进行排队。
 服务器可以使用多个实例来处理请求,代替单个实例的请求排队带来的效益问题。服务器创建一个Servlet类的多个Servlet实例组成的实例池,对于每个请求分配Servlet实例进行响应处理,之后放回到实例池中等待下此请求。这样就造成并发访问的问题。
 此时,局部变量(字段)也是安全的,但对于全局变量和共享数据是不安全的,需要进行同步处理。而对于这样多实例的情况SingleThreadModel接口并不能解决并发访问问题。因此,不建议实现SingleThreadModel接口,因为它在servlet规范中已经被废弃了。
2.使用同步块Synchronized,防止可能异步调用的代码块。这意味着线程需要排队处理。在使用同板块的时候要尽可能的缩小同步代码的范围,不要直接在sevice方法和响应方法上使用同步,这样会严重影响性能。
ServletContext是可以多线程同时读/写属性的,线程是不安全的。要对属性的读写进行同步处理或者进行深度Clone()。
   所以在Servlet上下文中尽可能少量保存会被修改(写)的数据,可以采取其他方式在多个Servlet中共享,比方我们可以使用单例模式来处理共享数据。
HttpSession(线程是不安全的)
   HttpSession对象在用户会话期间存在,只能在处理属于同一个Session的请求的线程中被访问,因此Session对象的属性访问理论上是线程安全的。
   当用户打开多个同属于一个进程的浏览器窗口,在这些窗口的访问属于同一个Session,会出现多次请求,需要多个工作线程来处理请求,可能造成同时多线程读写属性。
   这时我们需要对属性的读写进行同步处理:使用同步块Synchronized和使用读/写器来解决。
   对于每一个请求,ServletRequest由一个工作线程来执行,都会创建有一个新的ServletRequest对象,所以ServletRequest对象只能在一个线程中被访问。所以ServletRequest是线程安全的。ServletRequest对象在service方法的范围内是有效的,不要试图在service方法结束后仍然保存请求对象的引用。
对于集合, 使用线程安全的Vector代替ArrayList,使用Hashtable代替HashMap。
不要在Servlet中创建自己的线程来完成某个功能。
  Servlet本身就是多线程的,在Servlet中再创建线程,将导致执行情况复杂化,出现多线程安全问题。
,在多个servlet中对外部对象(比方文件)进行修改操作一定要加锁,做到互斥的访问
对于为什么要在doget方法里另上同步块,就是因为解决:当a,b同时访问时,如果a比b稍慢一些就会出现这样的情况,a页面空白,而b页面出现了服务端返回给a的结果,假如是比较敏感的个人信息不能让他人知道 的,而这种情况就会出现严重的安全问题,使用同步块并加锁可以做到a,b访问时两者的信息不会被对方及第三方知道!

 
 
线程安全性
  概述
  当对一个复杂对象进行某种操作时,从操作开始到操作结束,被操作的对象往往会经历若干非法的中间状态。这跟外科医生做手术有点象,尽管手术的目的是改善患者的健康,但医生把手术过程分成了几个步骤,每个步骤如果不是完全结束的话,都会严重损害患者的健康。想想看,如果一个医生切开患者的胸腔后要休三周假会怎么样?与此类似,调用一个函数(假设该函数是正确的)操作某对象常常会使该对象暂时陷入不可用的状态(通常称为不稳定状态),等到操作完全结束,该对象才会重新回到完全可用的状态。如果其他线程企图访问一个处于不可用状态的对象,该对象将不能正确响应从而产生无法预料的结果,如何避免这种情况发生是线程安全性的核心问题。单线程的程序中是不存在这种问题的,因为在一个线程更新某对象的时候不会有其他线程也去操作同一个对象。(除非其中有异常,异常是可能导致上述问题的。当一个正在更新某对象的线程因异常而中断更新过程后,再去访问没有完全更新的对象,会出现同样的问题) 
  线程安全性的级别
  就线程安全性进行讨论的时候存在这样一个问题:线程的安全性是存在多种级别的,每个人谈论的级别其实并不相同,仅仅说某段代码不具备线程安全性并不能说明全部问题。然而许多人对线程的安全性有一些想当然的预期,有些时候这些预期是合理而合法的,但有些时候不是。下面给出一些此类的预期: 
  通常认为多个线程读某对象时不会产生问题,问题只会在更新对象的时候出现,因为只有那时对象才会被修改, 从而有进入不稳定状态的危险。然而,某些对象具有内部状态,即使在读的时候内部状态也会被改变(比如某些对象有内部缓冲)。假如两个线程去读取这种对象,问题仍然会产生,除非该对象的读操作设计已经采用了合适的多线程处理方法。 
  通常认为更新两个相互独立的对象时,即使它们的类型相同也不会有问题。一般假设相互独立的对象之间是互不相关的,一个对象的不稳定状态并不会对另一个对象产生影响。然而,一些对象在内部是存在数据共享的(如静态的类数据,全局数据等),这使它们即使看上去没有什么逻辑上的关系,内部却依然存在联系。这种情况下,修改两个“相互独立”的对象怎么都会产生问题。考虑下面的情况: 
  void f( ) { std::string x; // Modify x. } 
  void g( ) { std::string y; // Modify y. }
  如果一个线程运行函数f()修改x,另一个线程运行函数g()修改y,这种情况下会出现问题吗?大部分人认为这是两个明显独立的对象,可以被同时改动而不会导致任何问题。但是,有一种可能性就是,两个对象内部存在共享数据,这完全依赖于std::string的实现,如果那样的话,同时改动便是有问题的了。实际上,如果两个对象内部存在共享数据的话,即使一个函数仅仅是读取对象,问题依然存在,因为改动另一个对象的函数可能触及内部的共享数据。 
  通常认为即便使用一个通用的资源池,获取资源的函数也不存在线程安全性的问题。例如: 
  void f() { char *p = new char[512]; // use the array p } 
  void g() { char *p = new char[512]; // use the array p }
  如果一个线程执行函数f(),另一个线程执行函数g(),两个线程可能同时使用操作符new去分配内存。在多线程环境中,只有假设new操作符的实现已经考虑到这种情况,从同一个内存池中获取内存也设计了正确的处理方法,才可以认为安全性得到保证。实际中,new操作符在内部确实会同步这些线程,因而每次调用都能够得到独立的内存分配而不损坏共享的内存池。与此类似的操作还有文件的打开、网络连接的发起以及其他资源的分配。 
  人们一般认为会引起问题的情形是一个线程要访问(读或更新)某对象时另一个线程正在更新它。全局对象尤其易于出现这种问题,局部对象出现问题的情况则少的多。比如: 
  std::string x; 
  void f() { std::string y; // modify x and y. }
  如果两个线程同时进入函数f(),它们拿到的对象y是不相同的,这是由于不同的线程拥有各自不同的栈,局部变量都在线程自己的栈上分配,因而每个线程都会拿到自己独立的局部变量副本。所以说,在f()中对y进行操作不会产生问题(假定操作独立的对象有安全保证),然而,全局对象x仅有一份两个线程都会触及的拷贝,对x的如上操作便会产生问题。局部变量也不是完全不会产生问题,因为每个函数都能够启动新的线程并且把局部变量的指针作为该线程的一个输入参数,比如: 
  void f ( ) { std : : string x ; startthread (somefunction , &x); startthread (somefunction , &x); }
  这里假设有一个名为startthread的库函数,它有两个参数,一个是线程入口函数的指针,一个是线程入口函数的参数的指针。在此情况下我们调用startthread启动两个线程,并且把x对象作为参数同时传给两个线程。如果somefunction()中会对x进行修改,则两个线程可能修改同一个对象,类似的问题便产生了。注意,这种情况是特别隐蔽的,因为somefunction()并没有什么特别的理由去考虑两次调用会传给它同一个对象,因而它不大可能做出应付这种情况的保护措施。 
  一般准则
  如果一个函数在其文档中没有特别注明具备线程安全性,则应该认为它不具备。许多库大量使用了内部的静态数据,除非它是为多线程应用所设计,否则要牢记其内部数据可能没有利用互斥量进行适当的保护。类似,如果类的成员函数在其文档中没有特别注明对于多线程应用是安全的话,则认为它不安全。两个线程去操作相同的对象会引起问题,这是显而易见的,然而,即使两个线程去操作不同的物体依然会引起问题。出于多种原因,许多类使用了内部静态数据或者在多个看上去明显不同的对象间共享实现细则, 
  以下给出几个一般准则: 
  操作系统提供的API具备线程安全性 
  POSIX线程标准要求C标准库中的大多数函数具备线程安全性,少数例外会在C标准中注明。 
  对于Windows提供的C标准库,如果所使用的版本没有问题,而且进行了正确的初始化,他们都是安全的。 
  C++标准库的线程安全性不是很明确,它在很大程度上依赖于使用的编译器。标准模板库线程安全性的SGI准则作为实际中的标准取得很大进展,但并不是统一的标准。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值