如何使用ThreadLocal(特别是与Servlet一起使用)?

时间:2015-05-07 06:18:14

标签: java multithreading servlets

我有一个使用框架的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对象,并且没有为每个请求/线程创建一个新对象,否则这将是一个非问题。

谢谢!

2 个答案:

答案 0 :(得分:2)

直接回答你的问题 - 听起来不错。 但是,我会考虑一些额外的观点:

(1)如果你有一个请求开始/结束的钩子 - 你可能想要在每个这样的请求结束时清除本地线程(例如,如果它是一个servlet我会使用一个过滤)。这有两个原因:为垃圾收集释放它,以及错误的情况(如果下一个请求遇到一些解析错误,它将看到一个空图像,而不是前一个用户&#39; s)

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

(3)作为旁注,人们也可以考虑其他解决方案 - 例如缓存(这可以帮助你作为副作用)。显然,这需要一些缓存大小,定期清除/更新等。

答案 1 :(得分:1)

你的代码是对的;你没有setter方法,但我想有一个拼写错误而不是getImage你要写setTitle()。 threadLocal还有一个remove方法,当你不再需要title属性时,你应该调用它。您可以找到一些使用示例herehere

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

我还建议你同时测试多个客户端,如果你有一个&#34;串行客户端&#34;如果您使用的是专用测试实例,最终可能会使用相同的服务器线程。