2016-03-28 13 views
1

Hallo Leute so habe ich dieses Stück CodeJava padding Leistung Zerschlagung

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(); 


    } 

}

Also, wenn ich es dauert etwa 11 Sekunden laufen, aber wenn ich qa1 die Auskommentierung es läuft in 3 Sekunden .I versucht um etwas im Internet zu finden, aber nichts Aufschlussreiches kam auf. Wie ich es verstehe, hat es etwas mit JVM-Optimierung zu tun und lange Q1 macht wahrscheinlich Speicher (oder Cache) Verteilung, wie besser. Wie auch immer meine Frage ist, weiß jemand, wo ich mehr darüber lesen kann. Dank

+0

Wo beziehst du die Variable 'q1'? – user2004685

+1

Wo deklarieren Sie 'res'? –

+0

Das ist die Thihng Sie nicht derzeit ist es in Zeile 4 auskommentiert, aber wenn Kommentar es die magische hapens – urag

Antwort

7

Leistung in Ihrem Beispiel durch false sharing degradiert wird - c1 und c2 Instanzen sind in der gleichen Cache-Zeile platziert und Threads müssen zum/vom Hauptspeicher bei jedem Zuwachs von verschiedenen Feldern/Belastungswerte spülen Cache zu halten Kohärenz nach der Mutual-Cache-Line-Copy-Invalidierung.

In Ihrem Fall ist es ausreichend, ein weiteres q1 langes Feld zu erklären, direkt nach c1c2 gehen zu einer anderen Cache-Zeile zu machen (die Größe ist nur 64 bytes für die x86 Familie). Danach wird die Cache-Verwaltung viel effizienter - Threads können verschiedene Cache-Zeilen verwenden und die Kopie der Cache-Zeile des anderen Threads nicht ungültig machen.

Es gibt viele Artikel, die der Hardware-Natur dieses Problems gewidmet sind (und Software-Möglichkeiten, es zu vermeiden). Der Umgang mit falscher Freigabe durch "Footprint Padding" -Lösung (wie Ihre) ist seit langem schwierig - Java-Plattform garantiert nicht, dass Felder Reihenfolge und Cache-Zeilenauffüllung in der Laufzeit genau wie erwartet in der Klassendeklaration sind. Selbst eine "kleine" Plattformaktualisierung oder der Wechsel zu einer anderen VM-Implementierung kann eine Lösung bremsen (weil Felder - insbesondere unbenutzte Dummies - Optimierungsobjekte sind).

Das ist, warum JEP-142 eingeführt wurde und @Contended Annotation was implemented in Java 8. Mit dieser Annotation können Sie konfigurieren, welche Felder der Klasse in verschiedenen Cache-Zeilen platziert werden sollen. Aber jetzt ist es nur ein VM-Hinweis ohne absolute Garantie über die Vermeidung von falschem Teilen in allen Situationen. Daher sollten Sie sich Ihren Code genau anschauen und sein Verhalten überprüfen (falls Ihre Anwendung natürlich für das Problem der falschen Freigabe sensitiv ist)

+0

Vielen Dank – urag