我已经阅读了有关ThreadLocal及其使用的SO线程的有趣讨论。
这个问题更倾向于设计时选择。我的情况就像这样
如果我在Web应用程序中有一个值对象,几乎所有步骤都需要在同一个线程中使用它。我可以想到两个界面设计选项,如下面
方法#1 使用方法参数传递。
到目前为止,我已经专注于提出一个接口,该接口可以具有带有值对象接口参数的方法。
例如:
public interface SomeDataProcessorInterface {
public void processSomething(SomeValueObjectInterface vo);
}
public interface SomeValueObjectInterface extends Serializable {}
Aproach#2 使用ThreadLocal
在这种方法中,我可以拥有一个没有方法参数的接口,只需创建一个静态类来使用threadlocal访问我的值对象。
例如:
public interface SomeDataProcessorInterface {
public void processSomething();
}
public interface SomeValueObjectInterface extends Serializable {}
public Class StaticClass {
private static ThreadLocal<SomeValueObjectInterface> threadLocalVO = new ThreadLocal<SomeValueObjectInterface>();
public static ThreadLocal getThreadLocal() {
return threadLocal;
}
哪种方法更好?为什么?
这些实现中的哪一个会减少内存泄漏的可能性?
这些实现中哪一个对Java垃圾收集器有利?
我通过其他帖子中的一些观点阅读但是如果我从头开始,我仍然不清楚哪种方法更好。
答案 0 :(得分:2)
这是一个设计问题,取决于您的情况。
如果SomeValueObjectInterface
在服务的业务逻辑的上下文中有意义,那么(我相信)它应该是一个参数,但是如果你把它当作横切关注点的数据(没有作为方面实现的方面),并且它不是业务逻辑的参数,然后使用ThreadLocal
。
顺便说一下,不要忘记清除ThreadLocal
块中的finally
,否则会遇到内存泄漏问题(很难找到)。
并且GC没有区别,因为如果您不忘记清除ThreadLocal
,那么两种方法中的对象都将在伊甸园中。
答案 1 :(得分:2)
如果您可以选择将某些内容作为方法参数传递或通过ThreadLocal存储,那么您应该将99.99999%的时间作为方法参数传递给它。 ThreadLocal存储的主要目的是处理一个间接调用方法的情况(意味着要求其他方法依次调用感兴趣的方法),需要将信息传递给内部方法,并且方法在中间没有提供传递该信息的便利渠道。如果没有“中间层”,可以简单地将附加参数添加到内部方法的签名中(通常内部方法只能由具有信息的代码调用,因此在方法定义和调用站点处添加参数应该没问题)。但是,在某些情况下,中间层存在并且必须使用。
对于示例,请考虑ShapeCollection
,其中包含DrawAll
方法,该方法在其所有形状上调用Draw
。应用程序定义了一些“很好”呈现缓慢的形状,因此为每个窗口添加一个选项,以选择是否将这些形状显示为占位符而不是详细渲染。如果Shape
设计时考虑到了这些需求,则其Draw
方法可能包含asPlaceHolder
参数,而ShapeCollection
DrawAll
可能已接受此类Shape
一个参数并将其传递给每个形状。但是,如果ShapeCollection
的设计师没有预料到这种需求,Draw
将无法支持它。
如果每个花式形状对象的Draw
方法仅用于更新一个特定窗口的目的,则形状可以保存对该窗口的引用,并使用该窗口的“使用占位符”选项来确定它应该自我渲染。但是,如果可能有多个窗口显示形状的视图,并且每个窗口都应支持其自己的渲染选项,则该方法可能无效。如果使用DrawingOptions
方法为剪贴板,打印机或其他介质渲染内容,这种方法也可能会出现问题。有一个窗口的绘图代码构造一个DrawAll
对象,创建一个线程本地引用,调用DrawAll
,然后擦除该线程本地引用将是不优雅的,但它将提供一个调用方法到Draw
将绘图选项传递给内部{{1}}方法 - 否则将无法实现。
答案 2 :(得分:1)
对于static
TheadLocal
,如果您忘记删除元素,则可能会泄漏内存。您可以通过在从方法返回之前删除元素来避免这种情况。我不推荐这种方法。
您的第一种方法已经是线程安全的,因为该参数仅对该方法调用是本地的。使用这个。