0

Meine Erwartung war, dass das Programm die Ausgabe "1000" zurückgeben würde.synchronisiert und ExecutorService auf Java 8

Jedes Mal, wenn das Programm ausgeführt wird, tritt jedoch eine andere Ausgabe auf.

Die Methode increment() der Counter-Klasse wurde synchronisiert. Wäre das nur nötig, um konkurrierende Messwerte zu vermeiden?

Was wäre der richtige Weg, um die 1000 Inkremente zu zählen?

package app; 

public class Counter { 

    private Integer value; 

    public Counter(int initialValue) { 
     value = initialValue; 
    } 

    public synchronized void increment() { 
     value = value + 1;   
    } 

    public int getValue() { 
     return value; 
    } 

} 

package app; 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class Main { 

    public static void main(String[] args) { 

     Counter contador = new Counter(0); 

     ExecutorService executor = Executors.newFixedThreadPool(10); 

     for(int i = 0; i < 1000; i++) { 
      executor.submit(() -> { 
       contador.increment(); 
      });  
     } 

     System.out.println(contador.getValue()); 

    } 

} 
+0

Diese Frage bezieht sich nicht direkt auf die Klasse Atomicinteger. –

Antwort

2

Dies ist, wie Ihre Hauptmethode aussehen sollte:

public static void main(String[] args) { 
    Counter contador = new Counter(0); 
    ExecutorService executor = Executors.newFixedThreadPool(10); 
    for(int i = 0; i < 1000; i++) { 
     executor.submit(() -> { 
      contador.increment(); 
     }); 
    } 
    executor.shutdown(); 
    try { 
     executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); 
    } catch (InterruptedException e) { 
    } 
    System.out.println(contador.getValue()); 
} 
+0

Verstanden. Vielen Dank. –

+0

Das stimmt, aber was ist mit einer Erklärung, warum es so aussehen sollte? – Malt

1

Die Antwort auf Ihre Frage ist, dass Sie nicht für alle Ihre Runnables warten vor dem Druck den Wert von Contador zu beenden.

Also manchmal nur 20 Anrufe wurden durchgeführt genannt zu erhöhen und manchmal 50 getan worden, etc

Edit:

näher Sehen, ich glaube, Sie mit Ihrer Thread-Sicherheit ein potenzielles Problem. Sie haben den Inkrementwert synchronisiert. Sollte die getValue-Methode übereinstimmen?

Zum Beispiel, wenn Thread A gerade inkrementiert wird, was sollte Thread B sehen, wenn er getValue aufruft? Sollte es den alten Wert sehen, oder sollte es warten, bis Thread A fertig ist, so erhält es den neuesten Wert?

+0

Verstanden. Vielen Dank. –

1

Ihre Logik ist in Ordnung.

Das Problem besteht darin, dass Sie den Wert des Indikators drucken, bevor die Threads die Inkrementierung beendet haben.

Code Um dies ändern:

for(int i = 0; i < 1000; i++) { 
    executor.submit(() -> { 
     contador.increment(); 
    });  
} 

executor.shutdown(); //Shut down the executor 

//Wait until the threads have stopped. A maximum of 1 minute is more than enough 
executor.awaitTermination(1, TimeUnit.MINUTES); 

System.out.println(contador.getValue()); //prints 1000 
+0

Oder verwenden Sie 'executor.shutdown(); while (! Executor.isTerminated()) {}' zu blockieren, bis alle Aufgaben ohne eine willkürliche Wartezeit erledigt sind. – Mena

+0

Verstanden. Vielen Dank. –

+0

@Mena 'executor.shutdown(); while (! Executor.isTerminated()) {}' ist eine schlechte Idee. Es wird zu viel Warten und hoher CPU-Auslastung führen. 'awaistTermination' ist besser. – Malt

Verwandte Themen