2

こんにちはみんな、私はこのコードを手に入れました

public class Padding {

  static class Pair {

        volatile long c1;
        // UN-comment this line and see how perofmance is boosted * 2
      //  long q1; //Magic dodo thingy

        volatile long c2;

  }

  static Pair p = new Pair();

  static class Worker implements Runnable {

        private static final int INT = Integer.MAX_VALUE/8;
        private boolean b;
        Worker(boolean b) {
              this.b = b;
        }

        public void run() {
              long start = System.currentTimeMillis();
              if (b) {
                    for (int i = 0; i < INT; i++) {
                          p.c1++;
                          res += Math.random();
                    }
              } else {
                    for (int i = 0; i < INT; i++) {
                          p.c2++;
                          res += Math.random();
                    }
              }
              long end = System.currentTimeMillis();
              System.out.println("took: " + (end-start) + " Result:" + p.c1+p.c2);
        }

  }


  public static void main(String[] args) {
        System.out.println("Starting....");
        Thread t1 = new Thread(new Worker(true));
        Thread t2 = new Thread(new Worker(false));

        t1.start();
        t2.start();


  }

}

したがって、実行すると約11秒かかりますが、qa1のコメントを外すと3秒で実行されます。インターネットで何かを見つけようとしましたが、十分な情報が得られませんでした。私が理解しているように、それはJVMの最適化と関係があり、長いq1はおそらくメモリ(またはキャッシュ)の分散をいくらか改善します。私の質問はいずれにせよ、誰かがそれについてもっと読むことができる場所を知っていますか. ありがとう

4

1 に答える 1

10

この例のパフォーマンスは、偽共有c1によって低下します。インスタンスは同じキャッシュ ラインに配置され、スレッドは、相互キャッシュ ライン コピーの無効化後にキャッシュの一貫性を維持するために、さまざまなc2フィールドの増分ごとにメイン メモリとの間で値をフラッシュ/ロードする必要があります。

あなたの場合、別のキャッシュラインに移動する直後にもう1つの長いフィールドを宣言するだけで十分です(このサイズはファミリq1専用です)。その後、キャッシュ管理がより効率的になります-スレッドは異なるキャッシュラインを使用でき、他のスレッドのキャッシュラインのコピーを無効にしません。c1c264 bytesx86

この問題のハードウェアの性質 (およびそれを回避するソフトウェアの方法) に専念する多くの記事があります。「フットプリント パディング」ソリューション (あなたのもののような) による誤った共有への対処は、長い間トリッキーでした。Java プラットフォームは、実行時のフィールドの順序とキャッシュ ラインのパディングが、クラス宣言で期待どおりになることを保証しません。「マイナーな」プラットフォームの更新または別の VM 実装への切り替えでさえ、ソリューションを妨げる可能性があります (フィールド、特に未使用のダミーは最適化の対象であるため)。

そのため、 JEP-142が導入され、@Contended注釈が に実装されましたJava 8。このアノテーションを使用すると、クラスのどのフィールドを異なるキャッシュ ラインに配置するかを構成できます。しかし今では、すべての状況での偽共有の回避に関する絶対的な保証のない単なる VM ヒントであるため、コードを注意深く見てその動作を確認する必要があります (もちろん、アプリケーションが偽共有の問題に敏感な場合)。

于 2016-03-28T08:53:23.523 に答える