2016-08-07 2 views
1

J'ai un programme dans lequel 3 threads tentent d'imprimer des nombres de 1 à 10 en séquence. J'utilise un CountDownLatch pour garder un compte.Impression de numéros en séquence à l'aide de 3 threads

Mais le programme arrête juste après l'impression 1.

Note: Je suis conscient du fait que l'utilisation AtomicInteger au lieu de Integer peut fonctionner. Mais je cherche à trouver le problème dans le code actuel.

public class Worker implements Runnable { 
    private int id; 
    private volatile Integer count; 
    private CountDownLatch latch; 

    public Worker(int id, Integer count, CountDownLatch latch) { 
     this.id = id; 
     this.count = count; 
     this.latch = latch; 
    } 

    @Override 
    public void run() { 
     while (count <= 10) { 
      synchronized (latch) { 
       if (count % 3 == id) { 
        System.out.println("Thread: " + id + ":" + count); 
        count++; 
        latch.countDown(); 
       } 
      } 
     } 
    } 

} 

Programme principal:

public class ThreadSequence { 
    private static CountDownLatch latch = new CountDownLatch(10); 
    private volatile static Integer count = 0; 

    public static void main(String[] args) { 
     Thread t1 = new Thread(new Worker(0, count, latch)); 
     Thread t2 = new Thread(new Worker(1, count, latch)); 
     Thread t3 = new Thread(new Worker(2, count, latch)); 

     t1.start(); 
     t2.start(); 
     t3.start(); 

     try { 
      latch.await(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

    } 
} 

programme édité avec AtomicInteger:

public class ThreadSequence { 
    private static AtomicInteger atomicInteger = new AtomicInteger(1); 

    public static void main(String[] args) throws InterruptedException { 
     Thread t1 = new Thread(new WorkerThread(0, atomicInteger)); 
     Thread t2 = new Thread(new WorkerThread(1, atomicInteger)); 
     Thread t3 = new Thread(new WorkerThread(2, atomicInteger)); 
     t1.start(); 
     t2.start(); 
     t3.start(); 

     t1.join(); 
     t2.join(); 
     t3.join(); 

     System.out.println("Done with main"); 
    } 
} 


public class WorkerThread implements Runnable { 
    private int id; 
    private AtomicInteger atomicInteger; 

    public WorkerThread(int id, AtomicInteger atomicInteger) { 
     this.id = id; 
     this.atomicInteger = atomicInteger; 
    } 

    @Override 
    public void run() { 
     while (atomicInteger.get() < 10) { 
      synchronized (atomicInteger) { 
       if (atomicInteger.get() % 3 == id) { 
        System.out.println("Thread:" + id + " = " + atomicInteger); 
        atomicInteger.incrementAndGet(); 
       } 
      } 

     } 
    } 
} 

Répondre

4

Mais le programme arrête juste après l'impression 1.

Non, ce n'est pas ce qui se passe. Aucun des threads ne se termine.

Vous avez un champ count dans chaque travailleur. Les autres threads n'écrivent pas dans ce champ.

Par conséquent, il n'y a qu'un seul thread, où if (count % 3 == id) { donne true, qui est celui avec id = 0. En outre, il s'agit du seul thread qui modifie le champ count et en le modifiant, (count % 3 == id) génère false lors des itérations de boucle suivantes, provoquant une boucle infinie dans les 3 threads.

Modifiez count à static pour résoudre ce problème.

Modifier

Contrairement à IntegerAtomicInteger est mutable. C'est une classe qui contient une valeur int qui peut être modifiée. En utilisant Integer chaque modification du champ remplace sa valeur, mais en utilisant AtomicInteger vous modifiez uniquement la valeur à l'intérieur de l'objet AtomicInteger, mais les 3 threads continuent à utiliser la même instance AtomicInteger.

+0

mis à jour le programme avec 'AtomicInteger' et il fonctionne sans AtomicInteger statique . Pourquoi? – Anurag

+1

@Anurag: Édité la réponse.La différence est la suivante: avec 'Integer' vous remplacez l'objet' Integer' lui-même, mais avec 'AtomicInteger' vous modifiez un champ de l'instance' AtomicInteger'. Essayez d'ajouter le modificateur 'final' dans les deux cas et voyez ce qui se passe ... – fabian

+0

De la source JDK de' AtomicInteger' je vois qu'il contient une valeur 'int' qui n'est pas finale. Mais dans le cas de 'Integer', il contient une valeur' int' qui est finale. Donc, dans le cas où 'Integer' avait un' int' qui était non-final et volatile, théoriquement cela fonctionnerait. C'est ce que vous vouliez dire? – Anurag

1

Votre "compte" est une variable différente pour chaque thread, il change si dans un thread doesn N'affectons pas le reste, et donc ils attendent tous que cela change, sans que personne ne puisse le faire.

1

Conserver le count en tant que membre statique dans la classe Worker - commun pour tous les objets de la classe.

0

Vous pouvez utiliser le code ci-dessous pour imprimer des numéros séquentiels en utilisant plusieurs threads -

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 

public class ThreadCall extends Thread { 

    private BlockingQueue<Integer> bq = new ArrayBlockingQueue<Integer>(10); 
    private ThreadCall next; 

    public void setNext(ThreadCall t) { 
     this.next = t; 
    } 

    public void addElBQ(int a) { 
     this.bq.add(a); 
    } 

    public ThreadCall(String name) { 
     this.setName(name); 
    } 

    @Override 
    public void run() { 
     int x = 0; 
     while(true) { 
      try { 
       x = 0; 
       x = bq.take(); 
       if (x!=0) { 
        System.out.println(Thread.currentThread().getName() + " =>" + x); 
        if (x >= 100) System.exit(0); // Need to stop all running threads 
        next.addElBQ(x+1); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     int THREAD_COUNT = 10; 
     List<ThreadCall> listThread = new ArrayList<>(); 

     for (int i=1; i<=THREAD_COUNT; i++) { 
      listThread.add(new ThreadCall("Thread " + i)); 
     } 

     for (int i = 0; i < listThread.size(); i++) { 
      if (i == listThread.size()-1) { 
       listThread.get(i).setNext(listThread.get(0)); 
      } 
      else listThread.get(i).setNext(listThread.get(i+1)); 
     } 

     listThread.get(0).addElBQ(1); 

     for (int i = 0; i < listThread.size(); i++) { 
      listThread.get(i).start(); 
     } 
    } 
} 

J'espère que cela résoudra votre problème