java:在类初始化期间初始化同一个类的静态字段

时间:2017-11-04 10:29:02

标签: java

看起来在启动应用程序时发生了死锁。 我有jstack文件,其中我发现一个线程调用TariffModelManager。< clinit>方法和其他多个线程调用TariffModelManager.getInstance()方法。 TariffModelManager的代码如下:

public class TariffModelManager{
    ...
    private static final TariffModelManager tariffModelManager = TariffModelManager.getInstance();
    ...
    private static volatile TariffModelManager _instance;

    private TariffModelManager(){}

    public static TariffModelManager getInstance() {
        if(_instance == null) {
            synchronized(TariffModelManager.class) {
                if(_instance == null) _instance = new TariffModelManager();
            }
        }
        return _instance;
    }
    ... 
}

我认为,通过调用getInstance()方法来初始化静态字段是一个明显的错误,其中检查了另一个字段(_instance),该代码在代码中有所描述,但实际发生了什么?

  1. 在类初始化期间,静态字段从上到下初始化;
  2. 我们试图初始化" tariffModelManager"场...
  3. 调用方法getInstance(),它检查_instance字段(但它没有被初始化!);
  4. 然后我们必须执行这个类的构造函数;
  5. 如果_instance字段已在构造函数中初始化,是否可以在静态字段初始化序列中将其设置为null?
  6. 我的问题不是如何解决这个问题,而是描述执行此代码时发生的事情!

    更新 Here我发现了详细的类初始化过程,但仍然不清楚,在哪个顺序" tariffModelManager"和" _instance"字段已初始化。

    谢谢!

1 个答案:

答案 0 :(得分:1)

您可以通过在两个静态字段上放置字段断点来验证发生了什么。

我稍微修改了你的样本:

class TariffModelManager {
    private static final TariffModelManager tariffModelManager = TariffModelManager.getInstance();
    private static volatile TariffModelManager _instance = new TariffModelManager();

    private TariffModelManager() {
        System.out.println("From Constructor: " + this);
    }

    public static TariffModelManager getInstance() {
        if (_instance == null) {
            synchronized (TariffModelManager.class) {
                if (_instance == null) {
                    _instance = new TariffModelManager();
                    System.out.println("Creating new instance: " + _instance);
                }
            }
        }
        return _instance;
    }

    public static void main(String[] args) {
        TariffModelManager.getInstance();

        System.out.println("tariffModelManager: " + TariffModelManager.tariffModelManager);
        System.out.println("_instance: " + TariffModelManager._instance);
    }
}

这是输出:

From Constructor: TariffModelManager@ea4a92b
Creating new instance: TariffModelManager@ea4a92b
From Constructor: TariffModelManager@3c5a99da
tariffModelManager: TariffModelManager@ea4a92b
_instance: TariffModelManager@3c5a99da

首先初始化静态字段tariffModelManager。调用getInstance方法时_instance为空 - 即默认值且尚未初始化。然后在该方法内初始化,并将值分配给tariffModelManager。然后根据静态初始化顺序再次重新初始化:Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

这很有趣,因为

class TariffModelManager {
    private static final TariffModelManager tariffModelManager = _instance;
    private static volatile TariffModelManager _instance = new TariffModelManager();

    private TariffModelManager() {
        System.out.println("From Constructor: " + this);
    }

    public static TariffModelManager getInstance() {
       return _instance;
    }
}

是无效的java,但静态方法为您提供了一种方法来解决问题。它(以及tariffModelManager将为null,不是真正意图,但仍然编译):

class TariffModelManager {
    private static final TariffModelManager tariffModelManager = getInstance();
    private static volatile TariffModelManager _instance = new TariffModelManager();

    private TariffModelManager() {
        System.out.println("From Constructor: " + this);
    }

    public static TariffModelManager getInstance() {
       return _instance;
    }
}