更新:解决方案后问题.
通常,同步是在JVM内串行化并行请求,例如
private static final Object LOCK = new Object();
public void doSomething() {
...
synchronized(LOCK) {
...
}
...
}
Run Code Online (Sandbox Code Playgroud)
在查看Web应用程序时,"JVM全局"范围上的某些同步可能会成为性能瓶颈,仅在用户的HttpSession范围内进行同步会更有意义.
以下代码是否可能?我怀疑同步会话对象是一个好主意,但听到你的想法会很有趣.
HttpSession session = getHttpServletRequest().getSession();
synchronized (session) {
...
}
Run Code Online (Sandbox Code Playgroud)
关键问题:对于处理来自同一用户的请求的所有线程
,是否保证会话对象是同一个实例?
看来会话对象本身并不总是相同,它依赖于servlet容器(Tomcat,Glassfish,...)的实现,并且该getSession()方法可能只返回一个包装器实例.
因此,建议使用存储在会话中的自定义变量作为锁定对象.
这是我的代码提案,欢迎提供反馈:
帮手类中的某个地方,例如MyHelper:
private static final Object LOCK = new Object();
public static Object getSessionLock(HttpServletRequest request, String lockName) {
if (lockName == null) lockName = "SESSION_LOCK";
Object result = request.getSession().getAttribute(lockName);
if (result == …Run Code Online (Sandbox Code Playgroud) 我有一些获取和设置会话属性的java代码:
Object obj = session.getAttribute(TEST_ATTR);
if (obj==null) {
obj = new MyObject();
session.setAttribute(obj);
}
Run Code Online (Sandbox Code Playgroud)
为了使这段代码成为线程安全的,我想将它包装在一个synchronized块中.但是我用什么作为锁定对象呢?使用会话是否有意义?
synchronized (session) {
Object obj = session.getAttribute(TEST_ATTR);
if (obj==null) {
obj = new MyObject();
session.setAttribute(obj);
}
}
Run Code Online (Sandbox Code Playgroud) 参考Brian Goetz的文章是否所有状态Web应用程序都被破坏了?对于IBM developerWorks,我想参考这段代码
HttpSession session = request.getSession(true);
ShoppingCart cart = (ShoppingCart)session.getAttribute("shoppingCart");
if (cart == null) {
cart = new ShoppingCart(...);
session.setAttribute("shoppingCart", cart);
}
doSomethingWith(cart);
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这段代码不是线程安全的,因为它使用了check-then-act模式.但我有一个疑问:
是不是HttpSession在第一行完全原子的创建或检索?原子,我的意思是如果两个线程调用request.getSession(),一个将阻止.虽然两者都会返回相同的HttpSession实例.因此,如果客户端(移动/ Web浏览器)制作两个或调用相同的Servlet(执行上面的代码片段),您将永远不会遇到不同线程看到不同值的情况cart.
假设我确信它不是线程安全的,那么如何使这个线程安全?会AtomicReference有效吗?例如:
HttpSession session = request.getSession(true);
AtomicReference<ShoppingCart> cartRef =
(<AtomicReference<ShoppingCart>)session.getAttribute("shoppingCart");
ShoppingCart cart = cartRef.get();
if (cart == null) {
cart = new ShoppingCart(...);
session.setAttribute("shoppingCart",
new AtomicReference<ShoppingCart>(cart));
}
doSomethingWith(cart);
Run Code Online (Sandbox Code Playgroud)
留言Merci!
我对在JSF 2.x中的requestScoped bean中创建会话有疑问.我知道我们不需要在JSF 2.x中创建会话,因为我们可以直接使用sessionScoped bean来放置用户所需的数据.但我最近介绍了一个JSF代码,其中开发人员创建了session的实例变量并从facescontext获取会话,如下所示
@ManagedBean
@RequestScoped
Public class someClass(){
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);
public void someFunction(){
//Some code here..
session.setAttribute("key","value");
//Some code here..
}
//rest of the code here...
}
Run Code Online (Sandbox Code Playgroud)
好吧,我告诉他们一个人不应该将"session"作为实例变量,也不需要在JSF 2中显式获取会话,而是使用sessionScoped bean.
对于第一个我给出了一个理由,"保持会话作为实例变量不是线程安全的",而对于第二个语句,我给出了"你正在为已经提供的JSF会话做一个解决方法".
我得到的反驳论点是,第一个原因"我们的网络应用是如此,因此不存在多线程问题".第二,我得到了"无论如何,一旦请求被处理,会话变量将被清除,所以这里没有任何错误.
我没有其他强项来纠正它.所以我的问题是,1)他们是否正确?2)我们应该以应该做的方式做任何其他具体原因吗?3)最后,任何可能促使他们使用这种方式的东西?
任何人都可以详细说明吗?请指正.谢谢
什么是避免jsp中的竞争条件同时不减慢进程的最佳方法.我试过isThreadSafe = false synchronized(session)
但有没有其他替代解决方案可用?
java ×4
concurrency ×2
servlets ×2
session ×2
java-ee ×1
jsf-2 ×1
jsp ×1
locking ×1
managed-bean ×1