1. 程式人生 > >靜態初始化中不能放入繁重計算,否則會變慢!

靜態初始化中不能放入繁重計算,否則會變慢!

vat 可變 必須 long sta 直接 示例 填充 images

技術分享圖片

在類初始化期間計算不可變數據結果,並將結果保存在static final字段中是一種非常常見的做法。實際上,這正是靜態初始化器的設計目標。

以下是在初始化時構建一些靜態表的典型示例:

public class StaticExample {
    static final long[] TABLE = new long[100_000_000];

    static {
        TABLE[0] = 0;
        for (int i = 1; i < TABLE.length; i++) {
            TABLE[i] = nextValue(TABLE[i - 1]);
        }
    }

    private static long nextValue(long seed) {
        return seed * 0x123456789L + 11;
    }

    ...
}

在我的JDK 11.0.1筆記本電腦上,靜態初始化程序在大約540毫秒內填充100M元素的數組。

現在讓我們簡單地刪除static並填充構造函數中的數組。

public class NonStaticExample {
    final long[] TABLE = new long[100_000_000];

    {
        TABLE[0] = 0;
        for (int i = 1; i < TABLE.length; i++) {
            TABLE[i] = nextValue(TABLE[i - 1]);
        }
    }

    private static long nextValue(long seed) {
        return seed * 0x123456789L + 11;
    }

    public static void main(String[] args) {
        new NonStaticExample();
    }
}

構造函數在138毫秒內填充類似的數組。幾乎快4倍!

為什麽靜態初始化器會變慢?這必須與JIT編譯有關。

解決方法非常簡單:

只是不要直接在未初始化的類中進行繁重的計算。如果將計算邏輯放在沒有靜態初始化程序的輔助類中,它將不會受到性能損失的影響。

public class StaticExample {
    static final long[] TABLE = Helper.prepareTable();

    private static class Helper {

        static long[] prepareTable() {
            long[] table = new long[100_000_000];
            for (int i = 1; i < table.length; i++) {
                table[i] = nextValue(table[i - 1]);
            }
            return table;
        }

        static long nextValue(long seed) {
            return seed * 0x123456789L + 11;
        }
    }
}

靜態初始化中不能放入繁重計算,否則會變慢!