我有一个使用框架的Web应用程序,我必须实现一个名为Plot的接口:
interface Plot {
Image getImage();
String getTitle();
}
我知道框架在getImage()
之前调用getTitle()
。在某些情况下,我需要生成图像的结果才能创建标题。
我知道如果我做这样天真的事情:
class MyNaivePlot implements Plot {
private String title;
public Plot getImage() {
title = "...";
}
public String getTitle() { return title; }
}
然后我可以介绍一个竞争条件。我似乎可以通过使用ThreadLocal
来解决这个问题,但我还没有看到足够的例子来了解我的解决方案是否正确(而且这些事情很难确定)。所以这就是我提出的:
class MyThreadLocalPlot implements Plot {
private ThreadLocal<String> title = new ThreadLocal<String>();
public Plot getImage() {
title.set("...");
}
public String getTitle() {
return title.get();
}
}
这足够吗?我正确使用ThreadLocal
吗?请注意,我只需要将标题挂起足够长的时间,直到getTitle()
调用它为止。在调用getImage()
之前,我并不关心它的价值是什么。
另请注意,我相信框架&#34;长寿&#34; MyPlot
对象,并且没有为每个请求/线程创建一个新对象,否则这将是一个非问题。
谢谢!
答案 0 :(得分:2)
直接回答你的问题 - 听起来不错。 但是,我会考虑一些额外的观点:
(1)如果你有一个请求开始/结束的钩子 - 你可能想要在每个这样的请求结束时清除本地线程(例如,如果它是一个servlet我会使用一个过滤)。这有两个原因:为垃圾收集释放它,以及错误的情况(如果下一个请求遇到一些解析错误,它将看到一个空图像,而不是前一个用户&#39; s)
(2)确保您的框架在这2个请求期间确实保证了单个线程(和同一台机器)。也许还要检查它是否适用于即将发布的版本以及水平扩展/集群。
(3)作为旁注,人们也可以考虑其他解决方案 - 例如缓存(这可以帮助你作为副作用)。显然,这需要一些缓存大小,定期清除/更新等。
答案 1 :(得分:1)
你的代码是对的;你没有setter方法,但我想有一个拼写错误而不是getImage
你要写setTitle()
。
threadLocal还有一个remove
方法,当你不再需要title属性时,你应该调用它。您可以找到一些使用示例here和here
在部署基于ThreadLocal的Plot版本之前,我建议你检查你的框架是否创建了一个或多个实例;只需使用计数器创建一个regolare类,并在get方法中增加计数器值;您可以记录它以查看计数器值如何随不同的调用而变化。如果您使用日志框架(如log4j或logback),我建议将线程名称放在日志中,以便您可以检查计数器值如何/更改时使用不同的检查。
我还建议你同时测试多个客户端,如果你有一个&#34;串行客户端&#34;如果您使用的是专用测试实例,最终可能会使用相同的服务器线程。