Java 中懒加载的正确实现方式

您所在的位置:网站首页 前端预加载怎么实现快捷键设置 Java 中懒加载的正确实现方式

Java 中懒加载的正确实现方式

2024-07-11 15:11| 来源: 网络整理| 查看: 265

1.通常懒加载初始化的典型实现方式:

public class LazyInit { public static Resource resource; public static Resource getResource() { if (resource == null) { resource = new Resource(); } return resource; } }

在单线程应用程序中,以上示例保证按预期工作。但在多线程应用程序可能有各种不同的结果。它可以按预期工作,它也可能多次初始化资源,它也可能发布部分对象(读取部分对象), 所以为不安全实现方式。

2. 安全的实现方式

public class LazyInit { public static Resource resource; public synchronized static Resource getResource() { if (resource == null) { resource = new Resource(); } return resource; } }

现在,resource由LazyInit类保护。只有一个线程可以进入此方法并检查resource是否已初始化,如果是,则返回当前实例。

3. 在某些情况下,您可能为了加快访问Resource实例的过程采取双重检查

public class LazyInit { public static Resource resource; public static Resource getResource() { if (resource == null) { synchronized (LazyInit.class){ if (resource == null){ resource = new Resource(); } } } return resource; } }

如果已异步初始化,则检查Resource ,否则您将同步初始化它。

看起来很好,但它不如(2.安全的实现方式)。在这种情况下,一个线程可以看到Resource部分加载,这意味着它与null不同,但它却还没有完全构造。

JSR-133表示,Java保证最终字段在构造完成之前“冻结”。我们来看看Resource文件。

public class LazyInit { public final int FINAL_VALUE; public int value; public Resource(){ FINAL_VALUE = 1; value = 1; } }

从LazyInit.getResource()方法检索Resource的一个线程实际上会获得部分对象:

... int aFinalValue = LazyInit.getResource()。FINAL_VALUE //保证1 int aValue = LazyInit.getResource()。value //可以是0 ...

用于双重检查锁定的解决方案需要易失性类型的资源。建议不要将此解决方案用于静态字段.

public class LazyInit { private volatile Resource resource; public Resource getResource() { Resource result = resource; if (result == null) { synchronized (this){ result = resource; if (result == null){ resource = new Resource(); } } } return resource; } }

易失性保证字段在所有线程中返回最新值并在写入时锁定它。请注意,我们将volatile值分配给普通变量,因此在检查时不知道它就不会改变, 所以将它赋值给一个临时变量。

4. 最快速初始化方式

public class EagerInit { private static Resource resource = new Resource(); public static Resource getResource() { return resource; } }

最终字段不仅承诺在构造完成之前被“冻结”,而且静态字段也必须在构造函数触发之前初始化。

该示例保证在使用resource之前实例化Resource.

上面的示例是线程安全的,但它是由JVM立即初始化的,并不是我们想要的。我们可以使用这些知识,但这并不是我们想要的。

5. Bill Pugh Singleton(单列模式)

事实证明,JVM对内部静态类的处理方式不同。它们保持隐藏,直到实际使用时才初始化实例对象。这个小信息驱使我们进入线程安全单例初始化的下一个例子

public class LazyInit { private static class Holder{ public static Resource resource = new Resource(); } public static Resource getResource(){ return Holder.resource; } }

这是Java中最推荐的延迟初始化方法。超级简单,超级安全。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3