2017-02-14 1 views
2

Voici le code:pourquoi le code à propos de thread affiche a = 1 et b = 3? et pourquoi ajouter un "volatile" n'a pas fonctionné?

public class ThreadCacheSample { 
    int a = 1; 
    int b = 2; 

    public void change() { 
     a = 3; 
     b = a; 
    } 

    public void print() { 
     if (a == 1 && b == 3) { 
      // why this is happening? 
      System.out.println("Thread[" + Thread.currentThread().getName() + "]Confused1 : a = 1, b = 3"); 
     } else if (a == 3 && b == 2) { 
      // why this is happening, too? 
      System.out.println("Thread[" + Thread.currentThread().getName() + "]Confused2 : a = 3, b = 2"); 
     } else { 
      System.out.println("Thread[" + Thread.currentThread().getName() + "] b=" + b + ";a=" + a); 
     } 
    } 

    public static void main(String[] args) { 
     // create many many threads 
     while (true) { 
      // create test every time, to make sure a is 1 and b is 2 again 
      final ThreadCacheSample test = new ThreadCacheSample(); 

      // one thread for changing 
      new Thread(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         Thread.sleep(10); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
        test.change(); 
       } 
      }).start(); 

      // one thread for printing 
      new Thread(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         Thread.sleep(10); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
        test.print(); 
       } 
      }).start(); 

     } 
    } 
}  

Le résultat devrait être a = 1, b = 2, ou a = 3, b = 3.

Mes questions sont les suivantes:

  1. Pourquoi aurais-je un résultat qui montre "a = 1, b = 3", ou "a = 3, b = 2"?

  2. Si j'ajoute « volatile » à a et b, pourquoi il ne fonctionne pas? Je pensais que le volatile rendrait chaque thread juste accéder à la mémoire principale, au lieu de leur propre mémoire de travail. Tellement volatile devrait être une solution. Mais la réalité me dit "volatile" n'est également pas une solution.

    public class ThreadCacheSample { 
        volatile int a = 1; 
        volatile int b = 2; 
        ... 
    } 
    

P.S. Ceci est pas une question sur la façon de résoudre le code. C'est à propos de pourquoi le résultat étrange apparaîtra?

+1

Vos déclarations d'impression sont erronées. Ils ne représentent pas la condition dans 'if'.En outre, vous pouvez d'abord capturer leurs valeurs dans les variables locales, puis opérer uniquement sur les variables locales. –

+0

Je suis désolé, que voulez-vous dire par "Vos déclarations d'impression sont fausses, elles ne représentent pas la condition dans si"? – songzhw

+1

Ils impriment tous les deux '' Confused1: a = 1, b = 3'. –

Répondre

5

Ajouter volatil augmente la visibilité des modifications de a et b individuellement (en plus d'ajouter une dépendance d'ordre entre la visibilité de leurs modifications). il ne pas, cependant, ajouter une sorte de « atomicité » à leur modification combinée. "volatile" ou non, la modification de a et la modification de b (ainsi que la lecture de a et la lecture de b) sont encore actions indépendantes!

deux de vos "confus" réponses sont possibles:

Cas 1:

  1. init, a == 1, b == 2
  2. tests de fil d'impression "a == 1"
  3. changement "fil des jeux a = 3"
  4. changement ensembles de fil "a = b" (3)
  5. tests de fil d'impression "b" de == 3
  6. confused1

Cas n ° 2:

  1. init, a == 1, b == 2
  2. changement jeux de fil "a = 3"
  3. tests de fil d'impression « a == 3"
  4. tests de fil d'impression "b de == 2"
  5. confused2

Notez que sans volatile, vous pouvez obtenir des réponses même whackier comme le fil d'impression voyant "a == 1, b == 3"!

+0

Est-ce que 'volatile' fait quelque différence ici? La façon dont il est codé, les deux threads ont accès aux mêmes variables. Si quelque chose il peut courir plus lentement en raison de 'write-through' sur chaque modification. –

+0

@JanezKuhar - Je ne suis pas sûr de ce que vous entendez par "l'accès aux variables", mais volatile exclut une possibilité, comme je l'ai mentionné dans ma dernière phrase. et oui, bien sûr, volatile a un impact sur les performances. – jtahlborn

+0

Vous avez raison, il ne peut pas imprimer a = 1, b = 3 si 'volatile 'est utilisé, mon mauvais. –