ThreadLocal与参数传递 - 在界面设计中选择什么?

时间:2013-10-10 20:59:16

标签: java interface thread-local

我已经阅读了有关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垃圾收集器有利?

我通过其他帖子中的一些观点阅读但是如果我从头开始,我仍然不清楚哪种方法更好。

3 个答案:

答案 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,如果您忘记删除元素,则可能会泄漏内存。您可以通过在从方法返回之前删除元素来避免这种情况。我不推荐这种方法。

您的第一种方法已经是线程安全的,因为该参数仅对该方法调用是本地的。使用这个。