2016-01-26 2 views
0

J'apprends actuellement la synchronisation en Java. Pour autant que j'ai compris, une méthode d'instance synchronisée acquiert un verrou sur son objet.Java Problème de synchronisation avec plusieurs threads partageant le même objet

Mon programme est un où 50 tâches sont faites et sont ensuite donné un fil. Chaque tâche ajoute un sou à un objet Compte créé à partir d'un compte Classe.

La classe de compte dispose d'un champ de données d'équilibrage et d'une méthode synchronisée pour le dépôt. Les 50 tâches ont un champ de compte qui pointe vers le même objet de compte (c'est-à-dire partage le compte). Une fois l'exécution exécutée, chaque tâche appelle la méthode d'instance account.deposit pour déposer 1 unité.

Je m'attends à ce que la balance se termine avec 50 unités. Étonnamment, le compte se retrouve avec 50 ou parfois d'autres soldes 14, 48, 33 etc.

class JavaStudy { 
    public static void main(String[] args){ 

     for (int j = 0; j < 10; j++) { 

      Account account = new Account(); 

      ExecutorService executorPool = Executors.newFixedThreadPool(50); 

      for (int i = 0; i < 50; i++) { 
       executorPool.execute(new DepositTask(account)); 
      } 

      executorPool.shutdown(); 

      while(!executorPool.isShutdown()){ 
      } 

      System.out.println(account.getBalance()); 
     } 
    } 
} 

classe de tâche de dépôt!

class DepositTask implements Runnable { 

    private Account account; 

    DepositTask(Account account){ 
     this.account = account; 
    } 

    @Override 
    public void run() { 
     account.deposit(1); 
    } 
} 

Classe de compte!

class Account { 

    private int balance = 0; 

    synchronized public void deposit(int amount){ 
     int balance = this.balance + amount; 
     this.balance = balance; 
    } 

    String getBalance(){ 
     return "Balance: " + balance; 
    } 
} 

Selon ce que je compris, à ce que je compris le compte devrait s'enfermer une fois une tâche account.deposit accès (1); Les autres tâches ne devraient pas pouvoir y accéder puisqu'elles partagent le même objet! D'une certaine façon cela ne va pas et je termine avec le résultat ci-dessous,

Balance: 20 
Balance: 47 
Balance: 50 
Balance: 42 
Balance: 27 
Balance: 24 
Balance: 50 
Balance: 29 
Balance: 13 
Balance: 12 

Process finished with exit code 0 

Toutes les idées sur ce qui se passe?

+1

"tandis que {} (executorPool.isShutdown()!)" - Il bloquent les méthodes pour atteindre en attente de la fin! S'il vous plaît ne le faites pas de cette façon! – Fildor

Répondre

5

Je suppose que vous n'attendez pas une terminaison différente de l'arrêt. Cela pourrait signifier que toutes les tâches n'ont pas été effectuées.

executorPool.shutdown(); 
executorPool.awaitTermination(1, TimeUnit.MINUTES); 
System.out.println(account.getBalance()); 

BTW En Java 8 vous pouvez simplifier avec

Account account = new Account(); 

InStream.range(0, 50).parallel() 
        .forEach(i -> account.deposit(1)); 

System.out.println(account.getBalance()); 
+0

@OldCurmudgeon merci pour la correction. –

+1

Merci! Cela a résolu le problème! L'arrêt empêche executerPool d'accepter d'autres tâches, mais les tâches en cours de traitement sont toujours en cours! C'est pourquoi, comme vous l'avez dit, la balance a montré des valeurs incohérentes! –