标签 多线程 下的文章

Servlet的多线程安全问题

public class MyServlet extends HttpServlet {
		final static int i = 0;
		public void doGet(HttpServletRequest req, HttpServletResponse res) {
			private HttpSession session = req.getSession();
			private ServletContext ctx = getServletContext();
			synchronized (ctx) {
				Object obj = ctx.getAttribute();
				// code to alter obj
			}
		}
	}

上面代码中的哪些变量是线程安全的?
选择:
* A. i
* B. session
* C. ctx
* D. req
* E. obj
* F. res
IBM 给出的答案是:
正确答案:
* A、C、D 和 F
说明:
静态变量 i 是线程安全的,因为它是 final(不能被修改),否则它将不是安全的。请求和响应对象的作用域只在请求的生命周期,因此它们也是线程安全的。会话和 ServletContext 对象可以从多个线程访问,同时处理多个请求,因此它们不是线程安全的。但在本例中,同步了 ServletContext 对象,因此它只能由一个线程一次访问。obj 不是线程安全的,因为即使同步了 ServletContext 对象,它的属性也没有同步。它们需要另外进行同步。因此,选项 B 和 E 是不正确的,而选项 A、C、D 和 F 是正确的。
Servlets的多线程安全
多线程占用资源少,处理速度快,提高了效率。
一些编码建议:
对变量和方法定义适当的访问方式, 例如单纯取值操作不会有多线程安全问题;
同步化所有访问重要数据的实例变量; 多线程下,如果操作的是一个变量,且兼有读写操作,
就要考虑加上同步,但同步不能乱加,否则会造成死锁问题。
并发需要注意的
并发的环境:资源处于一个并发的环境
共享资源:多个线程共享一个临界资源
全面同步:如有n个变量访问同一个资源,这n个变量都得同步。即多个锁一把钥匙,钥匙放在一个共享区域内
sychronized(this):粗粒度的锁。是将所有的路都加锁;
sychronized(object o1):细粒度的锁。只对对象中的变量加锁。效率较前面的高,但是较难控制。
读写需要互斥。
sychronized(this):this不能是基本数据类型,必须是Object.不锁对象的引用,而是对象的内存空间。
servlet中需要同步的:成员变量、文件、静态变量、数据库连接
一,servlet容器如何同时处理多个请求。
Servlet采用多线程来处理多个请求同时访问,Servlet容器维护了一个线程池来服务请求。
线程池实际上是等待执行处理的一组线程,也叫做工作者线程(Worker Thread),
Servlet容器使用一个调度线程来管理工作者线程(Dispatcher Thread)。
当容器收到一个访问Servlet的请求,调度者线程从线程池中选出一个工作者线程,将请求传递给该线程,
然后由该线程来执行Servlet的service方法。
当这个线程正在执行的时候,容器收到另外一个请求,调度者线程将从池中选出另外一个工作者线程来服务新的请求;
容器并不关心这个请求是否访问的是同一个Servlet还是另外一个Servlet;
当容器同时收到对同一Servlet的多个请求,那这个Servlet的service方法将以多线程方式并发执行。
二,Servlet容器默认采用单实例多线程的方式来处理请求,减少产生Servlet实例的开销,提升了对请求的响应。
对于Tomcat可以在server.xml中通过元素设置线程池中线程的数目。
就实现来说:
调度者线程类所担负的责任是调度线程,只需要利用自己的属性完成自己的责任。
而其他对象又依赖于该对象所承担的责任,需要得到该特定对象,那该类就是一个单例模式的实现了。
三,如何开发线程安全的Servlet
1,变量的线程安全:这里的变量指字段和共享数据(如表单参数值)。
a,将参数变量本地化:多线程并不共享局部变量.所以我们要尽可能的在servlet中使用局部变量。
例如:String user = request.getParameter(“user”);
b,使用同步块Synchronized,防止可能异步调用的代码块。这意味着线程需要队列处理。
在使用同板块的时候要尽可能的缩小同步代码的范围,不要直接在sevice方法和响应方法上使用同步,这样会严重影响性能。
2,属性的线程安全分析:ServletContext,HttpSession,ServletRequest对象的属性
ServletContext:(线程是不安全的)
ServletContext是可以多线程同时读/写属性的,线程是不安全的。要对属性的读写进行同步处理或者进行深度Clone()。
所以在Servlet上下文中尽可能少地保存频繁改写的数据,可以采取其他方式在多个Servlet中共享,比方我们可以使用单例模式来处理共享数据。
HttpSession:(线程是不安全的)
HttpSession对象在用户会话期存在,只能处理属于同一个Session的请求的线程,因此Session对象的属性访问理论上是线程安全的。
当用户打开多个同属于一个进程的浏览器窗口,在这些窗口的访问属于同一个Session,会出现多次请求,需要多个工作线程来处理请求,可能造成同时多线程读写属性,这时我们对属性的读写进行同步处理。
ServletRequest:(线程是安全的)
对于每一个请求,由一个工作线程来执行,都会创建有一个新的ServletRequest对象,所以ServletRequest对象只能在一个线程中被访问。ServletRequest是线程安全的。
注意:ServletRequest对象在service方法的范围内是有效的,不要试图在service方法结束后仍然保存请求对象的引用。
3,使用同步的集合类:
使用Vector代替ArrayList,使用Hashtable代替HashMap。
4,不要在Servlet中创建自己的线程来完成某个功能:
Servlet本身就是多线程的,在Servlet中再创建线程,将导致执行情况复杂化,出现安全问题。
5,在多个servlet中,对外部对象(例如文件)进行修改操作一定要加锁,做到互斥的访问
四,SingleThreadModel接口
javax.servlet.SingleThreadModel接口是一个标识接口,如果一个Servlet实现了这个接口,
则Servlet容器将保证在同时刻仅有一个线程可以在该servlet实例的service方法中执行,将其他所有请求进行排队。
服务器可以使用多个实例来处理请求,代替单个实例的请求排队带来的性能问题。
服务器可创建一个Servlet类的多个实例组成的实例池,对于每个请求分配Servlet实例进行响应,之后放回到实例池中等待下此请求。此时,局部变量(字段)也是安全的,但对于全局变量和共享数据是不安全的,需要进行同步处理。
而对于这种多实例的情况,使用SingleThreadModel接口并不能解决并发访问产生的问题,
且SingleThreadModel接口在servlet规范中已经被明确声明为deprecated了。

jedis多线程异常

多线程下使用jedis会报一些奇怪的错误

[2013.09.13 11:17:19.280]redis.clients.jedis.exceptions.JedisConnectionException: Unknown reply: 2
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Protocol.process(Protocol.java:71)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Protocol.read(Protocol.java:122)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:172)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Connection.getBulkReply(Connection.java:161)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Jedis.get(Jedis.java:65)
[2013.09.13 11:17:19.280]	at com.youku.index.web.manager.ProManager.getShowSearchCurve(ProManager.java:916)
[2013.09.13 11:17:19.280]	at com.youku.index.web.util.MergeFullkpi.mergeFull(MergeFullkpi.java:59)
[2013.09.13 11:17:19.280]	at com.youku.index.web.manager.ProManager.getAllShowVV(ProManager.java:836)
[2013.09.13 11:17:19.280]	at com.youku.index.web.action.ProAction.vrShow(ProAction.java:422)
[2013.09.13 11:17:19.280]	at sun.reflect.GeneratedMethodAccessor87.invoke(Unknown Source)
[2013.09.13 11:17:19.280]	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[2013.09.13 11:17:19.280]	at java.lang.reflect.Method.invoke(Method.java:597)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:161)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:563)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:76)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.DispatchFilterChain.doFilter(DispatchFilterChain.java:97)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:241)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:280)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:108)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:213)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:76)
[2013.09.13 11:17:19.280]	at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:158)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:241)
[2013.09.13 11:17:19.280]	at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:268)
[2013.09.13 11:17:19.280]	at com.caucho.server.port.TcpConnection.run(TcpConnection.java:586)
[2013.09.13 11:17:19.280]	at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:690)
[2013.09.13 11:17:19.280]	at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:612)
[2013.09.13 11:17:19.280]	at java.lang.Thread.run(Thread.java:662)

jedis并不是线程安全的,于是在程序中改为每个线程只使用一个jedis实例。
较好的解决办法是使用JedisPool,见官方文档:https://github.com/xetorthio/jedis/wiki/Getting-started
先初始化一个池,可以设置一些参数,如setMaxActive,setMaxIdle等:
查看源代码打印帮助
JedisPool pool = new JedisPool(new JedisPoolConfig(), “localhost”);
然后就可以从池中取出一个实例:

Jedis jedis = pool.getResource();
try {
  /// ... do stuff here ... for example
  jedis.set("foo", "bar");
  String foobar = jedis.get("foo");
  jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
  Set<String> sose = jedis.zrange("sose", 0, -1);
} finally {
  /// ... it's important to return the Jedis instance to the pool once you've finished using it
  pool.returnResource(jedis);
}
/// ... when closing your application:
pool.destroy();

用完要记得放回池,不用了需要销毁。
转自
http://www.rigongyizu.com/jedis-multithread-exception/
不过还没来得及实现,标记下……