2016-11-14 3 views
1

Java Multithreading springt Schleife und gibt falsches ErgebnisJava Multithreading springt Schleife und gibt falsches Ergebnis

package Threading; 

class DemoThread extends Thread{ //Thread Class 
    static int count=0; // variable incremented by both the threads 

    public DemoThread(String name) { 
     // TODO Auto-generated constructor stub 
     super(name); 
    } 

    public void run() { 
     for(int i=0;i<100000;i++) { 
      count++; 
      System.out.println(Thread.currentThread()+"Count"+count); // print thread operating on count variable 
      try { 
       Thread.sleep(1); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      }   
     }  
    } 
} 


public class MyThreadClass { 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub  
     DemoThread t1=new DemoThread("T1"); 
     DemoThread t2=new DemoThread("T2"); 
     t1.start(); 
     t2.start(); 
     try { 
      t1.join(); 
      t2.join(); //allowing both the threads to complee before main thread 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     System.out.println("Main Thread ends"+DemoThread.count); //final value of count   
    } 
} 

Den Endwert des Grafen 199.998 sein soll, aber es ist nicht das gewünschte Ergebnis. Warum die Threads die Schleifen fehlen ???

+0

Format Code richtig, bitte. –

Antwort

1

Sie müssen java.util.concurrent.atomic.AtomicInteger und keine gemeinsam genutzte statische int-Variable verwenden.

2

Es geschah, weil Faden T1 und T2 count zur gleichen Zeit wie die aktualisieren (Nebenläufigkeit):

Thread[T1,5,main]Count10 
Thread[T2,5,main]Count10 
Thread[T1,5,main]Count12 
Thread[T2,5,main]Count12 
Thread[T2,5,main]Count14 
Thread[T1,5,main]Count14 
Thread[T1,5,main]Count15 
Thread[T2,5,main]Count16 

sollten Sie AtomicInteger

verwenden und Ihren Code aktualisieren:

static int count=0; zu static AtomicInteger count= new AtomicInteger();

count++; bis count.incrementAndGet();

+0

aber warum ... zu einer Zeit wird nur 1 Thread runnable werden, d. H. Bekommt die CPU richtig ??? –

+0

Nein, Sie müssen mehr über Runnable, Thread und Parallel lernen. Ich denke http: //www.vogella.com/tutorials/JavaConcurrency/article.html # what-is-concurrency ist ein guter Artikel – Jerry06

+0

Es hat wirklich geholfen..Ich verstehe, es hängt von den CPU-Kernen können wir Nebenläufigkeit haben, da mehrere Threads Zugriff auf eine gemeinsame Daten gleichzeitig –

0

Problem

In Java, Multi-Threading, um Ihre Programme asynchrones Verhalten führt, müssen Sie Synchronität erzwingen, wenn Sie es brauchen.

Ohne Synchronisation hält nichts einen Thread an, von dem aus der Aufruf derselben Methode auf dasselbe Objekt zur gleichen Zeit zugegriffen werden kann. Dies ist bekannt als Race Condition, weil Threads gegeneinander laufen, um die Methode zu vervollständigen.

Die Ausgabe an Ihrem Programm:
enter image description here

Die erste Zeile der Ausgabe 2 gedruckt !? Der Grund hierfür ist, dass t1 den Wert von count geschrieben hat und es wurde vor dem Drucken abgebrochen. Beachten Sie, dass ein Thread nicht vorzeitig deaktiviert werden muss. OS tut dies trotzdem.

Wenn Sie die 1 st Linie und 4 th Linie feststellen, können Sie die Inkonsistenz sehen. Diese Art von Inkonsistenz wird in großen Programmen unvorhersehbar.

Hier sind Endergebnisse für mehrere Male ausgeführt.

enter image description here

enter image description here

Es ist nicht selbstverständlich, dass immer sind falsche Ergebnisse produziert genommen werden sollte. Nein, manchmal werden korrekte Ergebnisse produziert. Das bedeutet, dass die Ergebnisse unvorhersehbar sind.


Missverständnis auf?

Thread übersprungen Schleife.!? Nein, der Thread hat die Schleife nicht übersprungen. Verschiedene Threads haben auf denselben Wert zugegriffen, aber bevor sie ihren eigenen Wert schreiben konnte, schrieb ein anderer Thread den Wert und ging weiter. Daher hat es beim nächsten Zugriff auf den Wert den falschen Wert erhalten.

Dies ist bekannt als Reader Writer Problem


Lösung

In Ihrem Programm t1 und t2 zugreifen Ihre Zählung Variable mit unterschiedlichen Werten. Um zu verhindern, dass andere Threads run() aufrufen, bevor ein anderer Thread sie vervollständigt, fügen wir ein synchronisiertes Schlüsselwort vor der Methode hinzu.

synchronized public void run(){} 

Die synchronisiert Stichwort wacht über den Zustand von Rennbedingungen. Sobald ein Thread in die synchronisierte Methode eintritt, dürfen andere Threads die Methode erst verwenden, wenn der vorherige Thread die Methode beendet hat.

Hier ist die korrekte Ausgabe aufgrund synchronisiert Schlüsselwort. Hinweis: Ich habe 200 als Ende für Schleife verwendet.

enter image description here

enter image description here


Bonus

Wenn es proprietäre Methoden, die Sie verwenden, die als Eingabe in gemeinsam genutzten Daten übernehmen. Sie können Block synchronisiert verwenden

synchronized(objRef){ 
    //Method calling 
} 

objRef ist die Referenz des Objekts synchronisiert werden.


Wie in den Kommentaren empfohlen
[Empfohlene Lösung]

Sie Atomicinteger statt nativen int verwenden sollten. Verwenden Sie java.util.concurrent.atomic Paket.

Reference to java.util.concurrent.atomic

Statt static int count = 0; Verwendung static AtomicInteger count = new AtomicInteger(0); und statt count++; Verwendung count.incrementAndGet();

Atomicinteger inhärent synchronisiert ist.

Atomic Integer Reference Java Docs


+2

Verbose, aber gut erklärt. Die Schlussfolgerung sollte jedoch statt der Shotgun-Synchronisation AtomicInteger (der genau für den Zweck von OP implementiert ist) verwenden. –

+0

@SME_Dev Ich habe den AtomicInteger wie empfohlen hinzugefügt. –

+0

@SME_Dev natürlich wäre eine noch bessere Lösung für beide Threads, ihre eigenen zählen zu haben und sie zusammen zu addieren, wodurch alle Notwendigkeit für die Synchronisation während des Laufs beseitigt wird – bowmore