2010-08-15 28 views
5

J'expérimente Java Multi-Threading en utilisant la synchronisation sur la méthode de comparaison avec les variables atomiques (package java.util.concurrent.atomic).java synchronized sur la méthode Ne fonctionne pas?

Voici les classes:

// Interface ICounter.java 
     public interface ICounter { 
      public void increment(); 
      public void decrement(); 
      public int value(); 
     } 

// Class Counter.java 
    public class Counter implements ICounter { 
     private int c = 0; 

     @Override 
     public void increment() { 
      c++; 
     } 

     @Override 
     public void decrement() { 
      c--; 
     } 

     @Override 
     public int value() { 
      return c; 
     } 
    } 

// Class AtomicCounter.java 
    import java.util.concurrent.atomic.AtomicInteger; 

    public class AtomicCounter implements ICounter { 
     private AtomicInteger c = new AtomicInteger(0); 

     @Override 
     public void increment() { 
      c.incrementAndGet(); 
     } 

     @Override 
     public void decrement() { 
      c.decrementAndGet(); 
     } 

     @Override 
     public int value() { 
      return c.get(); 
     } 

     public long getIncrement() { 
      return c.incrementAndGet(); 
     } 
    } 

// Class MainProg.java 
    public class MainProg { 
     public static void main(String args[]) { 
      ICounter counter = new AtomicCounter(); 
        //ICounter counter = new SynchronizedCounter(); 
      Thread thread1 = new Thread(new CountRunner(counter)); 
      Thread thread2 = new Thread(new CountRunner(counter)); 

      thread1.start(); 
      thread2.start(); 
     } 
    } 

    class CountRunner implements Runnable { 
     private ICounter counter; 
     public CountRunner(ICounter counter) { 
      this.counter = counter; 
     } 

     public void run() { 
      while (true) { 
       counter.increment(); 
       System.out.println(Thread.currentThread().getName() + " count=" + counter.value()); 
       System.out.println("-------------------"); 
       try { 
        Thread.sleep(2000L); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 

Les résultats de l'exécution soit l'Atomic ou Synchronisé ne montrent pas que l'entier variable est thread-safe, par exemple:

Thread-0 count=1 
------------------- 
Thread-1 count=2 
------------------- 
Thread-0 count=3 
------------------- 
Thread-1 count=4 
------------------- 
Thread-0 count=5 
------------------- 
Thread-1 count=6 
------------------- 
Thread-0 count=7 
------------------- 
Thread-1 count=8 
------------------- 
Thread-0 count=10 
------------------- 
Thread-1 count=10 
------------------- 

A partir des résultats, les 2 dernières lignes montrent que les 2 threads accédaient à la même valeur de la variable entière de la classe du compteur. Peut-être qu'il me manque quelque chose ici?

Merci!

Répondre

4

Vous incrémentez la valeur en une étape, puis obtenez la valeur dans une autre étape. Bien que chacune de ces étapes soit garantie atomique par la classe AtomicInteger underling, le fait que vous effectuez deux opérations distinctes laisse la valeur que vous voyez dans votre instruction print à la merci de l'ordre d'exécution des threads. Pour pouvoir afficher précisément la valeur mise à jour par un thread donné, vous devez mettre à jour et obtenir la valeur résultante en une seule opération, ce que fait votre méthode getIncrement(). Le code qui vous donnerait les résultats attendus ressemblerait à ceci:

int changedValue = counter.getIncrement(); 
System.out.println(Thread.currentThread().getName() + " count=" + changedValue); 
2

Qu'est-ce que vous avez manqué est que votre classe AtomicCounter ne fonctionne correctement, et le comportement observé se produit becase les fils arbitrées entre l'appel à .increment() et .value():

------------------- 
Thread-0 increment -> value = 9 
------------------- 
Thread-1 increment -> value = 10 
------------------- 
Thread-0 print value <- 10 
------------------- 
Thread-1 print value <- 10 
------------------- 
4

parce que votre counter.increment() et System.out.println n'est pas une action atomique .

Thread 1    Thread2 

increment 

         increment 

         System.out.println // print 10 

System.out.println 
// print 10 too