示例:
public class UnsafeLazyInitialization { private static Resource resource; public static Resource getInstance() { if (resource == null) resource = new Resource(); // unsafe publication return resource; } static class Resource { } }
一般情况下,估计大家都会这么写代码,在非并发环境中,这个getInstance方法会工作的很好,但是放到并发环境中,问题就来了,比如竞态条件,但这里还存在另外一个问题,即另一个线程可能会看到对部分构造的Resource实例的引用。
简单点来说,就是线程A在访问getInstance方法时,发现resource为null,于是就resource设置为一个新实例,在这个过程中,线程B也调用getInstance方法,发现resource不为空,因此就直接使用这个resource实例了。看起来貌似没有问题,但是因为线程A实例化resource的操作和线程B读取resource实例的操作之间不存在Happens-Before关系,所以,在线程B使用resource实例时,resource实例也许还未构造完成,这就导致了线程B看到的resource实例不正确的状态。
解决这个问题的一个简单办法就是使用同步,这也是我们经常会使用的办法:
public class SafeLazyInitialization { private static Resource resource; public synchronized static Resource getInstance() { if (resource == null) resource = new Resource(); return resource; } static class Resource { } }
下面再来看看另一种解决办法,书中称之为延迟初始化占位类模式,我认为这个方法很巧妙:
public class ResourceFactory { private static class ResourceHolder { public static Resource resource = new Resource(); } public static Resource getResource() { return ResourceFactory.ResourceHolder.resource; } static class Resource { } }
标签:初始化,resource,Resource,class,安全,实例,static,java,public From: https://www.cnblogs.com/easy77/p/16929433.html