关于HTTPSession,我正在使用Java Servlet,并且没有框架。我已经阅读了有关AtomicReferences的内容,但不清楚如何使用它来使此代码线程安全。我以为可以简单地将updateSessionHashSet标记为同步来提供安全性是否正确?我了解不建议您这样做效率低下。还有什么其他选项和语法?
HTTPServlet内部:
private void updateSessionHashSet(HttpServletRequest req){
HashSet<String> hs = req.getSession().getAttribute("theHashSet");
String csv = req.getParameter("theCsv");
String[] arr = csv.split(",");
for(int i = 0; i < arr.length; i++){
hs.add(arr[i].trim());
}
}
public void doPost(HttpServletRequest req,HttpServletResponse res) throws IOException {
updateSessionHashSet(req);
}
答案 0 :(得分:1)
您所引用的帖子告诉您HTTPSession为共享状态,当多个线程可以对其进行修改时,您必须小心。在这里,线程干扰的机会是,如果您以某种方式有来自同一用户的两个并发POST调用此方法。您可以通过类似的方式处理它
private void updateSessionHashSet(HttpServletRequest req){
String csv = req.getParameter("theCsv");
Set<String> hs = new HashSet<String>();
String[] arr = csv.split(",");
for(int i = 0; i < arr.length; i++){
hs.add(arr[i].trim());
}
req.getSession().setAttribute("theHashSet", hs);
}
这样,您可以先将新的哈希集放到本地变量中,然后代码自动覆盖对会话的theHashSet属性的引用。如果两个线程正在调用相同的代码,则一个或另一个将获胜,但两个不会混杂在一起(这似乎与您发布的代码可能发生的情况一样)。
或者,您可能希望链接文章上的某些答案建议并同步HttpSession对象,但是由于您正在同步该应用程序实例本地的Java对象,因此您必须注意应用程序分布在多个节点上的情况。同步意味着使用共享锁,并且在JVM之间没有共享。
对于IT部门来说,将应用程序部署到多个实例以避免单点故障确实是很常见的。您可以通过将会话固定到特定服务器来解决同步问题,但这会使负载平衡变得困难。
通过这种方式在HttpSession中存储东西可能不是最佳计划,您应该将其保存在某种数据存储中。具有安全并发的最佳方法是最小化可变状态的数量。 HttpSession不能用作长期存储。
有关Java EE内容的线程安全性的准则,我有一个相关的答案here。
答案 1 :(得分:0)
当您的班级中有个共享的可变成员成员时,您应该关心线程安全。
局部变量存储在每个线程自己的堆栈中,因此局部变量永远不会在线程之间共享。这与局部原始变量有关。
案例1,本地线程安全原语:
XCEventGenerator
对对象的本地引用更加复杂。引用本身未共享。但是,引用的对象存储在共享堆中。
如果本地创建的对象永不转义该方法,则它是线程安全的。
案例2,本地线程安全引用:
class Processor {
public void threadSafeMethod() {
int count = 0;
count++;
}
}
案例3个非线程安全的共享的可变的成员:
class Processor {
public void threadSafeMethod() {
StringBuilder sb = new StringBuilder("Text");
appendPoint(sb);
}
public void appendPoint(StringBuilder b) {
b.append(". ");
}
}
案例4个线程安全的共享的不可变成员:
class Processor {
private StringBuilder sb; // shared mutable reference
public void nonThreadSafeMethod() {
sb = new StringBuilder("Text");
appendPoint(sb);
}
public void appendPoint(StringBuilder b) {
b.append(". ");
}
}