转载

静态初始化中不能放入繁重计算,否则会变慢!

在类初始化期间计算不可变数据结果,并将结果保存在static final字段中是一种非常常见的做法。实际上,这正是静态初始化器的设计目标。

以下是在初始化时构建一些静态表的典型示例:

<b>public</b> <b>class</b> StaticExample {
    <b>static</b> <b>final</b> <b>long</b>[] TABLE = <b>new</b> <b>long</b>[100_000_000];

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

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

    ...
}

在我的JDK 11.0.1笔记本电脑上,静态初始化程序在大约540毫秒内填充100M元素的数组。

现在让我们简单地删除static并填充构造函数中的数组。

<b>public</b> <b>class</b> NonStaticExample {
    <b>final</b> <b>long</b>[] TABLE = <b>new</b> <b>long</b>[100_000_000];

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

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

    <b>public</b> <b>static</b> <b>void</b> main(String[] args) {
        <b>new</b> NonStaticExample();
    }
}

构造函数在138毫秒内填充类似的数组。几乎快4倍!

为什么静态初始化器会变慢?这必须与JIT编译有关,详细分析点击标题见原文。

解决方法非常简单:

只是不要直接在未初始化的类中进行繁重的计算。如果将计算逻辑放在没有静态初始化程序的辅助类中,它将不会受到性能损失的影响。

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

    <b>private</b> <b>static</b> <b>class</b> Helper {

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

        <b>static</b> <b>long</b> nextValue(<b>long</b> seed) {
            <b>return</b> seed * 0x123456789L + 11;
        }
    }
}
原文  https://www.jdon.com/52038
正文到此结束
Loading...