【问题标题】:How to avoid synchronization and object creation?如何避免同步和对象创建?
【发布时间】:2013-11-08 21:11:23
【问题描述】:
  1. 我使用 JOGL 在 Java 中编写了一个 OpenGL 应用程序。我试图完全避免在主应用程序阶段创建对象,因为它可能会导致 GC 引起的小周期性延迟。

  2. 我想用我自己的包装一些 JOGL 的方法。想象一个方法void method(int[] result, int offset),它接收指向数组的指针和偏移量,并在指定索引处将一个整数值放入其中。我想用简单的int getResult()包装它

  3. 所以我需要在某个地方创建一个临时数组,而且我必须提前做(根据1)。

  4. 但是如果它将存储在包含此包装方法的类的字段中,这将迫使我制作包装方法synchronized。我知道大部分单线程访问的时间同步不应该产生很大的开销,但我仍然想知道是否有更好的解决方案。

注意事项:

  • 同步不是答案,3.000.000 个 empty 同步块,只是 monitorenter-monitorexit 需要 17 毫秒。如果你想保持 60 fps,你只有 16.(6)。

由于我没有足够的权力来投票,我发现欣赏 Dave 答案的唯一方法是编写一个演示:

class Test {
    private static final int CYCLES = 1000000000;

    int[] global = new int[1];
    ThreadLocal<int[]> local = new ThreadLocal<int[]>();

                 void _fastButIncorrect() { global[0] = 1; }
    synchronized void _slowButCorrect()   { global[0] = 1; }

    void _amazing()   {
        int[] tmp = local.get();
        if( tmp == null ){
            tmp = new int[1];
            local.set(tmp);
        }
        tmp[0] = 1;
    }

    long fastButIncorrect() {
        long l = System.currentTimeMillis();
        for (int i = 0; i < CYCLES; i++) _fastButIncorrect();
        return System.currentTimeMillis() - l;
    }
    long slowButCorrect() {
        long l = System.currentTimeMillis();
        for (int i = 0; i < CYCLES; i++) _slowButCorrect();
        return System.currentTimeMillis() - l;
    }
    long amazing() {
        long l = System.currentTimeMillis();
        for (int i = 0; i < CYCLES; i++) _amazing();
        return System.currentTimeMillis() - l;
    }
    void test() {
        System.out.println(
                        "fastButIncorrect cold: " + fastButIncorrect() + "\n" +
                        "slowButCorrect   cold: " + slowButCorrect()   + "\n" +
                        "amazing          cold: " + amazing()          + "\n" +
                        "fastButIncorrect  hot: " + fastButIncorrect() + "\n" +
                        "slowButCorrect    hot: " + slowButCorrect()   + "\n" +
                        "amazing           hot: " + amazing()          + "\n"
        );
    }
    public static void main(String[] args) {
        new Test().test();
    }
}

在我的机器上结果是:

fastButIncorrect cold: 40
slowButCorrect   cold: 8871
amazing          cold: 46
fastButIncorrect  hot: 38
slowButCorrect    hot: 9165
amazing           hot: 41

再次感谢戴夫!

【问题讨论】:

  • 1.听起来像一个严重过早的担忧。
  • @MattBall 的评论很到位。您是否有显示 GC 滞后的分析器输出?除非您有相当水平的对象带宽,否则这应该不是问题。
  • 请避免讨论问题的性质。没有同步且不创建对象的解决方案吗?
  • 为什么不为每个线程创建一个包装器?这是一个问题——渲染本身是多线程的吗? Jogl 是否完全支持这一点?
  • @StefanHaustein 也许这是最好的解决方案,但它会稍微改变架构。

标签: java performance concurrency logic


【解决方案1】:

如果你没有太多线程,你可以使用 ThreadLocal:

ThreadLocal<int[]> tmpArrayThreadLocal = new ThreadLocal<int[]>();

使用代码:

int[] tmpArray = tmpArrayThreadLocal.get();
if( tmpArray == null ){
   tmpArray = new int[100];
   tmpArrayThreadLocal.set(tmpArray);
}
method(tmpArray, 5)

您可以通过将 ThreadLocal 封装在另一个类中来清理代码。

【讨论】:

  • 你知道对性能有何影响吗?您需要为每次通话都执行此操作,对吗?
  • 我已经测试过了,性能很棒!我检查了他们是如何实现的,并且似乎他们将数据存储在线程本身中并在数组中使用固定的简单偏移量。所以这就是我想要的!非常感谢您的回答,我正在谷歌上搜索该课程 - 从未听说过,但它看起来非常有用且很有希望。
  • 请注意您创建的线程数,因为在线程结束之前不会对这些数据进行垃圾收集。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 2016-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多