2016-08-07 17 views
1

Ich habe ein Programm, wo 3 Threads versuchen, Zahlen in der Reihenfolge von 1 bis 10 zu drucken. Ich verwende eine CountDownLatch, um eine Zählung zu behalten.Drucken von Zahlen in Folge mit 3 Threads

Aber das Programm stoppt kurz nach 1.

Hinweis Druck: Ich bin mir bewusst, dass AtomicInteger statt Integer mit arbeiten können. Aber ich suche das Problem im aktuellen Code.

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(); 
       } 
      } 
     } 
    } 

} 

Hauptprogramm:

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(); 
     } 

    } 
} 

Herausgegeben Programm mit 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(); 
       } 
      } 

     } 
    } 
} 

Antwort

4

Aber das Programm stoppt kurz nach dem Drucken 1.

Nein, das ist nicht, was passiert. Keiner der Threads wird beendet.

Sie haben ein eigenes Feld count in jedem Arbeiter. Andere Threads schreiben nicht in dieses Feld.

Daher gibt es nur einen Thread, if (count % 3 == id) { ergibt true, die mit id = 0 ist. Auch dies ist der einzige Thread, der das Feld count ändert und dessen Änderung bewirkt, dass false in nachfolgenden Schleifeniterationen ergibt, was eine Endlosschleife in allen 3 Threads verursacht.

Ändern Sie count zu static, um dies zu beheben.

bearbeiten

Im Gegensatz zu IntegerAtomicInteger ist wandelbar. Es ist eine Klasse, die einen int Wert enthält, der geändert werden kann. Unter Verwendung von Integer ersetzt jede Änderung des Felds dessen Wert, aber unter Verwendung von AtomicInteger ändern Sie nur den Wert innerhalb des Objekts AtomicInteger, aber alle 3 Threads verwenden weiterhin dieselbe Instanz AtomicInteger.

+0

das Programm mit 'AtomicInteger' aktualisiert lösen wird und es funktioniert, ohne statische Atomicinteger . Warum? – Anurag

+1

@Anurag: Bearbeitete die Antwort.Der Unterschied ist: mit 'Integer' ersetzen Sie das 'Integer'-Objekt selbst, aber mit' AtomicInteger' modifizieren Sie ein Feld der 'AtomicInteger'-Instanz. Versuchen Sie, in beiden Fällen den 'final'-Modifizierer hinzuzufügen und zu sehen, was passiert ... – fabian

+0

Aus der JDK-Quelle von' AtomicInteger' sehe ich, dass es einen 'int'-Wert enthält, der NICHT endgültig ist. Aber im Falle von "Integer" enthält es einen "int" -Wert, der endgültig ist. Also, falls 'Integer' ein' int' hatte, das nicht final und flüchtig war, würde es theoretisch funktionieren. Das ist, was du meintest? – Anurag

1

Ihre "count" ist eine andere Variable für jeden Thread, so dass es in einem Thread zu ändern doesn Den Rest beeinflussen sie nicht, und so warten sie alle darauf, dass sich etwas ändert, ohne dass jemand es schafft.

1

Behalten Sie die count als statisches Mitglied in der Worker-Klasse - allgemein für alle Objekte in der Klasse.

0

Sie unter Code verwenden können, fortlaufende Nummern mit mehreren Threads drucken -

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(); 
     } 
    } 
} 

Ich hoffe, das Ihr Problem