Java hat einige Klassen für numerische Sicherheitszähler unter Multithreading entwickelt. Diese Klassen werden als atomare Klassen bezeichnet.
java.util.concurrent.atomic.AtomicBoolean;java.util.concurrent.atomic.AtomicInteger;java.util.concurrent.atomic.AtomicLong;java.util.concurrent.atomic.AtomicReference;
Das Folgende ist ein inkrementeller Test, der AtomicInteger- und gewöhnliche int-Werte unter Multithreading mit junit4 vergleicht.
Vollständiger Code:
package test.java;import java.util.concurrent.CountDownLatch;import java.util.concurrent.atomic.AtomicInteger;import org.junit.Assert;import org.junit.Before;import org.junit.Test;/** * Testen Sie die Inkrementierungsoperation von AtomicInteger und dem gewöhnlichen int-Wert unter Multithreading*/public class TestAtomic { // Atomic Integer inkrementieren Objekt öffentlich statisch AtomicInteger counter_integer; // = new AtomicInteger(0); // Eine Variable vom Typ int public static int count_int = 0; @Before public void setUp() { // Erste Einrichtungsarbeiten durchführen, bevor alle Tests beginnen counter_integer = new AtomicInteger(0 ); } @Test public void testAtomic() throws InterruptedException { // Anzahl der erstellten Threads int threadCount = 100; Wie oft schleifen andere verbundene Threads intern? Objekt des Hauptthreads Objekt; (der Hauptthread wartet, bis die Ausführung aller Unterthreads abgeschlossen ist, bevor er fortfährt) CountDownLatch Latch_n = new CountDownLatch(threadCount); // Andere Unterthreads erstellen und starten für (int i = 0; i < threadCount; i++) { Thread thread = new AtomicIntegerThread(latch_1, thread.start(); } long startNano = System.nanoTime(); ; // Warten, bis andere Threads fertig sind, // long endNano = System.nanoTime(); counter_integer.get(); // Assert.assertEquals("sum is not equal to threadCount * loopCount, test failed", sum, threadCount * loopCount("--------testAtomic() ); Wird voraussichtlich gleich sein------------"); System.out.println("Zeitaufwändig: " + ((endNano - startNano) / (1000 * 1000)) + "ms" ); System.out.println("threadCount = " + (threadCount) + ";"); System.out.println("loopCount = " + (loopCount) + ";"); + (sum) + ";"); } @Test public void testIntAdd() throws InterruptedException { // Anzahl der erstellten Threads int threadCount = 100; Wie oft schleifen andere verbundene Threads intern? Objekt des Hauptthreads Objekt; (der Hauptthread wartet, bis die Ausführung aller Unterthreads abgeschlossen ist, bevor er fortfährt) CountDownLatch Latch_n = new CountDownLatch(threadCount); // Andere Unterthreads erstellen und starten für (int i = 0; i < threadCount; i++) { Thread thread = new IntegerThread(latch_1, thread.start(); } long startNano = System.nanoTime(); ); // Warten, bis andere Threads beendet sind; // long endNano = System.nanoTime(); Assert.assertNotEquals( "Summe gleich ThreadCount * LoopCount, testIntAdd() Test fehlgeschlagen", Summe, ThreadCount * LoopCount("-------testIntAdd(); Erwartet, dass die beiden ungleich sind- - -------"); System.out.println("Zeitaufwändig: " + ((endNano - startNano) / (1000*1000))+ "ms"); System.out.println("threadCount = " + (threadCount) + ";"); System.out.println("loopCount = " + (loopCount) + ";"); + (Summe) + „;“); AtomicIntegerThread(CountDownLatch Latchdown, int LoopCount) { this.latch = Latch; This.loopCount = LoopCount; } @Override Public void Run() { // Warten auf Signalsynchronisierung try { This.latch . wait(); } Catch (InterruptedException e) { e.printStackTrace(); // for (int i = 0; i < loopCount; i++) { counter_integer.getAndIncrement(); } // Benachrichtigung wird um 1 dekrementiert; ; public IntegerThread(CountDownLatch Latch, CountDownLatch Latchdown, int LoopCount) { this.latch = Latch; this.latchdown = Latchdown; This.loopCount = LoopCount; } // for (int i = 0; i < loopCount; i++) { count_int++ } // Benachrichtigung wird um 1 dekrementiert Latchdown.countDown();
Die Ausführungsergebnisse auf einem normalen PC ähneln den folgenden:
--------------testAtomic(); Es wird erwartet, dass zwei gleich sind------------------Zeitaufwändig: 85366msthreadCount = 100;loopCount = 10000600;sum = 1000060000;-----------------testIntAdd(); Es wird nicht erwartet, dass die beiden gleich sind------------- ----Zeitaufwändig: 1406msthreadCount = 100;loopCount = 10000600;sum = 119428988;
Daraus ist ersichtlich, dass der Effizienzunterschied zwischen der AtomicInteger-Operation und der int-Operation etwa das 50- bis 80-fache beträgt. Dieser Vergleich dient nur als Referenz.
Wenn festgestellt wird, dass es sich um eine Single-Thread-Ausführung handelt, sollte int verwendet werden. Die Effizienz der int-Operationsausführung unter Multithreading ist recht hoch und dauert 1 Milliarde Mal nur 1,5 Sekunden.
(Unter der Annahme, dass die CPU 2 GHz, Dual-Core und 4 Threads hat und das theoretische Maximum 8 GHz beträgt, gibt es theoretisch 8 Milliarden Taktzyklen pro Sekunde.
Eine Milliarde Java-Inkremente dauern 1,5 Sekunden, was 12 Milliarden Operationen entspricht. Rechnerisch verbraucht jeder Zyklus 12 CPU-Zyklen.
Persönlich denke ich, dass die Effizienz der C-Sprache auch mehr als 4 Taktzyklen erfordern sollte (Beurteilung, Ausführung des internen Codes, automatische Inkrementierungsbeurteilung, Sprung).
Die Prämisse ist: JVM und CPU sind nicht radikal optimiert.
)
Tatsächlich ist die Effizienz von AtomicInteger nicht gering. Eine Milliarde Mal verbraucht 80 Sekunden, und eine Million Mal dauert es etwa ein Tausendstel, also 80 Millisekunden.