Java 从子类访问时的最终字段状态

Java 从子类访问时的最终字段状态,java,Java,我看到了一种奇怪的行为,根据JMM,这种行为似乎不应该发生。 我有一个B类,它扩展了A类,A类中的最后一个受保护的字段,在B类在其构造函数中访问的构造函数中初始化 但是,在非常罕见的情况下,当在B中访问时,我会得到一个NPE。 有什么想法吗 守则的一部分: class AsyncReplicationSourceGroup extends AbstractReplicationSourceGroup{ public AsyncReplicationSourceGroup(Dynamic

我看到了一种奇怪的行为,根据JMM,这种行为似乎不应该发生。 我有一个B类,它扩展了A类,A类中的最后一个受保护的字段,在B类在其构造函数中访问的构造函数中初始化

但是,在非常罕见的情况下,当在B中访问时,我会得到一个NPE。 有什么想法吗

守则的一部分:

class AsyncReplicationSourceGroup extends AbstractReplicationSourceGroup{

    public AsyncReplicationSourceGroup(DynamicSourceGroupConfigHolder groupConfig){
        super(groupConfig);
        createReplicationChannels();  
    }

    protected void createReplicationChannels(){
        //...
        specificLogger.finest("created channel");  // this is where the NPE is thrown from
        //...
    }
}

abstract class AbstractReplicationSourceGroup{

    protected final Logger specificLogger;

    public AbstractReplicationSourceGroup(DynamicSourceGroupConfigHolder groupConfigHolder){
        specificLogger = Logger.getLogger(Constants.LOGGER_REPLICATION_GROUP + "." + _groupConfigHolder.getConfig().getName());
        //...
    }

}

无法从单独发布的代码中确定,但是如果您确定记录器本身为null(并且您没有从内部错误地看到NPE,例如specificLogger.finest),那么最有可能的解释是logger.getLogger出于某种原因偶尔返回null


我认为问题不在于线程化,因为一旦构造的对象可见,只要构造函数中没有引用泄漏,就可以保证在构造函数中分配给的最终字段可见。

从您的示例中很难判断,但我的问题是,它必须处理日志框架和train-craft调用,才能在构造函数中初始化它。这是日志程序声明应该始终为私有静态最终版的原因之一。您可以发布一个最小的失败示例吗?否则我们在猜测。代码是什么样的?你能提供一个复制异常的示例吗?你能发布一个代码示例吗?我无法重现这种行为。“非常罕见的情况”对我来说意味着线程安全问题。