2017-10-17 4 views
0

Warum ist value korrekt eingestellt, obwohl wir verschiedene Sperren in verschiedenen Threads verwenden?Warum ist der Wert korrekt eingestellt, obwohl wir verschiedene Sperren in verschiedenen Threads verwenden?

public class MyThread implements Runnable { 
    static String a = "LOCK"; 
    static String b = "LOCK"; 
    int id; 
    static int value = 0; 

    MyThread(int id) { 
     this.id = id; 
    } 

    @Override 
    public void run() { 
     if (id == 0) { 
      synchronized (a) { 
       for (int i = 0; i < Main.N; i++) 
        value = value + 3; 
      } 
     } else { 
      synchronized (b) { 
       for (int i = 0; i < Main.N; i++) 
        value = value + 3; 
      } 
     } 
    } 
} 

public class Main { 
    static final int N = 100000; 
    static int ITER = 100; 

    public static void main(String[] args) { 
     Thread threads[] = new Thread[2]; 
     boolean sw = true; 
     for (int j = 0; j < ITER; j++) { 
      MyThread.value = 0; 
      for (int i = 0; i < 2; i++) 
       threads[i] = new Thread(new MyThread(i)); 
      for (int i = 0; i < 2; i++) 
       threads[i].start(); 
      for (int i = 0; i < 2; i++) { 
       try { 
        threads[i].join(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      if (MyThread.value != 2 * 3 * N) { 
       System.out.println("i was different than " + 2 * 3 * N + ", it is " + MyThread.value); 
       sw = false; 
      } 
     } 
     if (sw) 
      System.out.println("Something is strange"); 
    } 
} 
+2

Warum gehen Sie davon aus, dass sich ein Thread-Sicherheitsfehler garantiert zeigt? Praktisch die Definition von Thread-Sicherheits-Bugs ist, dass sie funktionieren können, bis sie nicht funktionieren. –

+0

Ein * möglich * Grund ist, dass der erste Thread beendet wird, bevor der zweite überhaupt startet. –

+1

@jack Sie benötigen den aufrufenden Code für den Kontext. Ohne sie könnte die Antwort lauten "weil die Threads nacheinander ablaufen". –

Antwort

3

Java-Zeichenfolgenliterale werden intern gespeichert, um Speicher zu sparen.

Ihre zwei "LOCK" Strings (und damit die zwei Objekte, die Sie sperren) sind eigentlich das gleiche Objekt.

Dies ist (einer der Gründe), warum Sie niemals Grundelemente sperren sollten.

+0

Ich bin so blind :( – jack

+0

Und mindestens, 'new Object()' ist eine bessere Wahl für ein Objekt zu synchronisieren als jede andere. Obwohl die Zeit in das Lernen 'java.util.concurrent.locks' investieren ist Ich werde definitiv Dividenden zahlen !! – corsiKa

3

Nie String als Schlösser verwenden, wie es auch die gleiche Instanz eines anderen String sein kann, weil der String-Pool.

In Ihrem Fall sind Ihre zwei "LOCK" Strings eigentlich das gleiche Objekt.

+0

Der erste Satz ist der allgemeine Fall: 2 'String' -mit dem gleichen Inhalt- * kann * das gleiche Objekt sein, wenn sie beide * interniert * wurden und daher nicht als Sperren verwendet werden sollten. –

Verwandte Themen