Java 如何使用ThreadLocal(特别是servlet)?

Java 如何使用ThreadLocal(特别是servlet)?,java,multithreading,servlets,Java,Multithreading,Servlets,我有一个web应用程序,它使用一个框架,我必须在其中实现一个名为Plot的接口: interface Plot { Image getImage(); String getTitle(); } 我知道框架在调用getTitle()之前调用getImage()。在某些情况下,我需要图像生成的结果来创建标题 我知道如果我做了这样幼稚的事情: class MyNaivePlot implements Plot { private String title; public Plot

我有一个web应用程序,它使用一个框架,我必须在其中实现一个名为Plot的接口:

interface Plot {
  Image getImage();
  String getTitle();
}
我知道框架在调用
getTitle()
之前调用
getImage()
。在某些情况下,我需要图像生成的结果来创建标题

我知道如果我做了这样幼稚的事情:

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(); 
  }
}
类MyThreadLocalPlot实现Plot{
私有ThreadLocal title=new ThreadLocal();
公共绘图getImage(){
标题.集合(“…”);
}
公共字符串getTitle(){
返回title.get();
}
}
这是否足够?我是否正确使用
ThreadLocal
?请注意,我只需要标题挂起足够长的时间,直到
getTitle()
调用它。我不在乎它的值在那之后是什么,也不在乎调用
getImage()
之前是什么

还要注意的是,我相信框架“长寿”于
MyPlot
对象,并且不会为每个请求/线程创建一个新的框架,否则这将不是问题


谢谢

您的代码非常正确;您没有setter方法,但我想可能是输入错误,您想编写
setTitle()
而不是
getImage
。 threadLocal还有一个
remove
方法,当您不再需要title属性时,应该调用该方法。您可以找到一些用法示例和

在部署基于ThreadLocal的Plot版本之前,我建议您检查您的框架是否创建了一个或多个实例;只需创建一个带有计数器的regolare类,并在get方法中增加计数器值;您可以记录它以查看计数器值如何随不同调用而变化。如果您使用log4j或logback之类的日志框架,我建议将线程名称放在日志中,这样您就可以检查计数器值如何/是否随着不同的检查而改变


我还建议您同时使用多个客户端对其进行测试,如果您有一个“串行客户端”,那么如果您使用的是专用的测试实例,那么最终可能会使用相同的服务器线程。

要直接回答您的问题,听起来不错。 但是,我会考虑一些附加点:

(1) 如果您有一个用于请求开始/结束的钩子,那么您可能希望在每个这样的请求结束时清除本地线程(例如,如果是servlet,我会使用过滤器)。这有两个原因:释放它用于垃圾收集,以及在出现错误的情况下(这样,如果下一个请求遇到解析错误,它将看到一个空图像,而不是前一个用户的)

(2) 确保您的框架在这两个请求期间确实保证了一个线程(和同一台机器)。也许还可以检查它是否适用于即将发布的版本,以及水平缩放/集群


(3)作为一个旁注,你也可以考虑其他解决方案——例如缓存(这将有助于你作为副作用)。显然,这需要一些关于缓存大小、定期清除/更新等方面的考虑。

这个类是如何调用的?它是否为每个请求实例化?或者只有一次?然后我可以介绍一个比赛条件:你能详细说明一下吗?这个类有多少个实例?它们是如何产生的?线程之间如何以及为什么共享它们?线程局部变量应该是static finalTo chburd和JB:我想我在帖子中回答了这些问题。多个线程/请求之间只共享一个plot对象;我可以在末尾添加一个remove()。我保证这两个方法都是用同一个线程调用的。再次感谢!谢谢,我将在其中添加一个remove()。以及关于确认只有一个实例的好建议;我几乎可以肯定这是事实。正如我提到的,我已经尝试过测试我的解决方案是否有效,但这很棘手,因为使用了线程池。它似乎工作正常,但只是想确认我没有遗漏任何东西。再次感谢!