【问题标题】:Ensure static variable is immediately cached by all threads确保所有线程立即缓存静态变量
【发布时间】:2018-05-30 17:17:04
【问题描述】:

我有大量使用静态变量的线程,该变量在同步块中延迟初始化。初始化是内存密集型的,因此理想情况下只想这样做一次。我知道线程访问他们自己缓存的静态变量副本,但它需要一些时间才能被缓存,所以最初每个线程都进入初始化块。即使它是同步的,这也可能导致内存不足错误。

有没有办法强制静态变量在第一个线程初始化后立即可供所有新线程使用?

代码(简化):

class TestingThread extends Thread {

    private static Templates transformTemplateRequest = null;
    private static final Object lockObj = new Object();
    private Document xslt;

    public void run() {

        //Document xslt initialized
        Transformer requestTransformer = null;
        synchronized (lockObj) {
            if (transformTemplateRequest == null) {
                TransformerFactory tf = TransformerFactory.newInstance();
                Source xsltSource = new DOMSource(xslt);
                transformTemplateRequest = tf.newTemplates(xsltSource);
            }
        }
        requestTransformer = transformTemplateRequest.newTransformer();
        //other work
    }
}

【问题讨论】:

  • 如果保证你需要这个对象,那么延迟初始化有什么好处呢?为什么不创建变量final,并在创建任何线程之前在static 块中对其进行初始化?
  • 我会将 transformTemplateRequest 保留在 AtomicReference 中,并使用单独的线程对其进行初始化。然后任何其他线程都可以检查该值并在不为空时使用它。
  • 您正在尝试重新发明惰性线程安全的单例。只需检查一下 Java 中的一些线程安全实现即可:en.wikipedia.org/wiki/Double-checked_locking
  • 谢谢 - 静态初始化器是个好主意,但它被添加到一个非常大的现有应用程序中 - 代码 sn-p 被简化,并且在加载类时可能无法满足依赖关系.
  • “即使它是同步的,这也可能导致内存不足错误。”不可以。显示的代码只允许单个线程初始化transformTemplateRequest。一旦该线程退出synchronized 块,任何其他线程都会看到分配给transformTemplateRequest 的非空值

标签: java multithreading


【解决方案1】:

如果 stmt 的话,我会把它包装在另一个中:

if (transformTemplateRequest == null) {
    synchronized (lockObj) {
        if (transformTemplateRequest == null) {
            TransformerFactory tf = TransformerFactory.newInstance();
            Source xsltSource = new DOMSource(xslt);
            transformTemplateRequest = tf.newTemplates(xsltSource);
        }
    }
}

如果变量已经设置,这将完全绕过同步块。

【讨论】:

  • 如果transformTemplateRequest 未标记为volatile,此代码可能会导致问题:en.wikipedia.org/wiki/Double-checked_locking
  • 谢谢,仔细检查听起来正是我想要的。不知道这种模式 - 很好的链接和关于将 transformTemplateRequest 标记为 volatile 的好点。
猜你喜欢
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 2018-08-05
  • 1970-01-01
  • 1970-01-01
  • 2013-03-29
  • 2019-10-20
  • 1970-01-01
相关资源
最近更新 更多