- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
引用 Brian Goetz 的文章 Are all stateful Web applications broken?对于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);
据我所知,这段代码不是线程安全的,因为它使用了check-then-act 模式。但是我有一个疑问:
第一行中 HttpSession
的创建或检索不是完全原子的吗?原子的意思是,如果两个线程调用 request.getSession()
,其中一个会阻塞。尽管两者都会返回相同的 HttpSession
实例。因此,如果客户端(移动/网络浏览器)对同一个 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);
谢谢!
最佳答案
你的代码仍然不是线程安全的:
ShoppingCart cart = cartRef.get();
if (cart == null) {
cart = new ShoppingCart(...);
session.setAttribute("shoppingCart",
new AtomicReference<ShoppingCart>(cart));
}
这是因为两个 Thread 都可以获得一个 null 的 cart
,创建新的购物车对象,并将它们插入到 session 中。其中一个将“获胜”,这意味着一个将设置 future 请求使用的对象,但另一个将 - 对于此请求 - 使用完全不同的 cart
对象。
要使其成为线程安全的,您需要按照您引用的文章中的惯用语做这样的事情:
while (true) {
ShoppingCart cart = cartRef.get();
if (cart != null) {
break;
}
cart = new ShoppingCart(...);
if (cartRef.compareAndSet(null, cart))
break;
}
使用上面的代码,如果两个使用相同HttpSession
的Thread同时进入while
循环,就不存在导致它们使用不同的数据竞争购物车
对象。
要解决 Brian Goetz 没有在文章中解决的部分问题,即首先如何将 AtomicReference
放入 session 中,有一个简单且 可能(但不保证)线程安全的方式来做到这一点。即,实现一个 session 监听器并将空的 AtomicReference
对象放入 session 的 sessionCreated
方法中:
public class SessionInitializer implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event){
HttpSession session = event.getSession();
session.setAttribute("shoppingCart", new AtomicReference<ShoppingCart>());
}
public void sessionDestroyed(HttpSessionEvent event){
// No special action needed
}
}
只有在 session 创建时才会为每个 session 调用一次此方法,因此这是进行 session 所需的任何初始化的合适位置。不幸的是,Servlet 规范不要求在监听器中调用 sessionCreated()
和调用 service()
之间存在happens-Before 关系> 方法。所以这显然不能保证是线程安全的,并且不同 Servlet 容器之间的行为可能会有所不同。
因此,即使有一个小的机会,一个给定的 session 可以同时处理多个请求,这也不够安全。最后,在这种情况下,您需要使用某种锁来初始化 session 。你可以这样做:
HttpSession session = request.getSession(true);
AtomicReference<ShoppingCart> cartRef;
// Ensure that the session is initialized
synchronized (lock) {
cartRef = (<AtomicReference<ShoppingCart>)session.getAttribute("shoppingCart");
if (cartRef == null) {
cartRef = new AtomicReference<ShoppingCart>();
session.setAttribute("shoppingCart", cartRef);
}
}
执行完上述代码后,您的 Session 就被初始化了。 AtomicReference
保证在 session 中,并且以线程安全的方式。您可以在同一个同步块(synchronized block)中更新购物车对象(并一起免除 AtomicReference
—— 只需将购物车本身放入 session 中),或者您可以更新 AtomicReference
上面显示的代码。哪一个更好取决于你需要做多少初始化,执行这个初始化需要多长时间,在同步块(synchronized block)中做一切是否会对性能造成太大的伤害(最好用a来确定探查器,而不是猜测),等等。
通常,在我自己的代码中,我只使用同步块(synchronized block)而不使用 Goetz 的 AtomicReference
技巧。如果我确定同步导致了我的应用程序中的 active 问题,那么我可能会通过使用 AtomicReference
技巧等技巧将一些更昂贵的初始化从同步块(synchronized block)中移出。
另请参阅:Is HttpSession thread safe, are set/get Attribute thread safe operations?
关于java - 理解 Goetz 关于 HttpSession 的线程安全的文章,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/750165/
我正在尝试创建一个 Django 网站,每次在本地主机上运行/articles/api/article 页面时:我都会收到此回溯: Environment: Request Method: GET R
我正在尽最大努力理解开放图谱协议(protocol)中的一切含义阅读 FB page在上面和 OGP Page .这在 FB 和 OGP 的世界中究竟意味着什么: Note that the Open
我的 HTML/CSS 中存在页脚与文章内容重叠的问题。是的,我一直在网上搜索但似乎没有任何效果,我希望你知道它有什么问题。我在这里做了一个codepen: CodePen LINK
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
我可以将变量作为警报显示在函数中,但无法将变量传递给文章。我做错了什么? 我知道“a”保存了正确的信息,因为我已经通过警报显示了它。 我尝试使用以下方式传递变量:placeholderContent.
这个问题已经有答案了: Rails article helper - "a" or "an" (6 个回答) 已关闭 3 年前。 是否有类似 [#pluralize in ActiveSupport]
这个问题已经有答案了: Rails article helper - "a" or "an" (6 个回答) 已关闭 3 年前。 是否有类似 [#pluralize in ActiveSupport]
我有以下型号。 Book has Articles (Article has foreign key to Book) Article has Images (Article has upto #ma
我创建了一个页面,该页面显示了单个 类别下的所有帖子,即如果我单击类别音乐,我将获得与音乐类别相关的所有文章。 但我的目标是创建一个过滤选项,它可以过滤掉某些类别,并且只显示与您过滤的类别相关的所有帖
我使用这样的代码: $query = "SELECT introtext FROM #__content WHERE alias = '$alias'"; $db->setQuery($query);
我在主页上设置了一些特色文章。显示的所有文章似乎都剩下太多填充。我知道足以进入 css 并在 layout.css 上编辑 .itembody 的填充或边距,但似乎没有任何改变。我希望我的文章通过模块
ORM 中存储文章及其修订的最佳实践是什么?当我自己用SQL存储时,我曾经有以下结构: articles [id, parent_id, name, text] 通过parent_id,我可以轻松识
我的 HTML : Interest About Interest
我正在用jade构建一个nodejs、express、mongodb博客。 我的文件夹结构是:项目/ 模块/ 观点/ 索引.jade 应用程序.js 文章提供者内存.js 文章provider-mon
我的问题比较具体,至少对我来说是这样。具体是因为在做了很多搜索之后我找不到任何有用的东西。因此,正如标题所说,我正在寻找一种算法,它会发现输入中给出的两篇文章是否“匹配”,但不是通常的字符串匹配意义上
关闭。这个问题是off-topic .它目前不接受答案。 9年前关闭。 锁定。这个问题及其答案是locked因为这个问题是题外话,但具有历史意义。它目前不接受新的答案或互动。 我无法弄清楚动态编程的原
我有这个问题。我正在建立一个社交网站,我必须在两栏中创建帖子。父容器是一个部分,元素“post”是样式为 float: left 的文章。我如何让滑到那些较短的下方创建的空白空间的帖子? 最佳答案 c
这里有几个关于文件与数据库的问题,但我仍然不确定使用什么以及为什么在我的案例中应该使用它。 我的网站上有很多 HTML 文章(长度在几百到几千字之间)。在数据库 (MySQL) 中,我有一个没有搜索索
微信公众号文章 Semantic Kernel —— LangChain 的替代品? [1] ,它使用的示例代码是Python ,他却发了这么一个疑问: 支持的语言对比(因为 Sem
我想编写一个 polymer 元素来显示一些 WordPress 文章。 http://www.jsv-lippstadt.de/?json=get_category_posts&slug=app
我是一名优秀的程序员,十分优秀!