Java has designed some classes for numerical safety counters under multi-threading. These classes are called atomic classes. Some of them are as follows:
java.util.concurrent.atomic.AtomicBoolean;java.util.concurrent.atomic.AtomicInteger;java.util.concurrent.atomic.AtomicLong;java.util.concurrent.atomic.AtomicReference;
The following is an incremental test comparing AtomicInteger and ordinary int values under multi-threading, using junit4;
Complete 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;/** * Test the increment operation of AtomicInteger and ordinary int value under multi-threading*/public class TestAtomic { // Atomic Integer increment object public static AtomicInteger counter_integer; // = new AtomicInteger(0); // A variable of type int public static int count_int = 0; @Before public void setUp() { // Perform initial setup work before all tests start counter_integer = new AtomicInteger(0 ); } @Test public void testAtomic() throws InterruptedException { // Number of threads created int threadCount = 100; // How many times other affiliated threads loop internally int loopCount = 10000600; // Control the auxiliary object of the affiliated thread; (other await threads wait for the main thread to start) CountDownLatch latch_1 = new CountDownLatch(1); // Control the auxiliary object of the main thread Object; (the main thread waits for all subsidiary threads to finish running before continuing) CountDownLatch latch_n = new CountDownLatch(threadCount); // Create and start other subsidiary threads for (int i = 0; i < threadCount; i++) { Thread thread = new AtomicIntegerThread(latch_1, latch_n, loopCount); thread.start(); } long startNano = System.nanoTime(); // Let other waiting threads start latch_1.countDown (); // Wait for other threads to finish latch_n.await(); // long endNano = System.nanoTime(); int sum = counter_integer.get(); // Assert.assertEquals("sum is not equal to threadCount * loopCount, test failed", sum, threadCount * loopCount); System.out.println("--------testAtomic(); Expected to be equal------------"); System.out.println("Time consuming: " + ((endNano - startNano) / (1000 * 1000)) + "ms"); System.out.println("threadCount = " + (threadCount) + ";"); System.out.println("loopCount = " + (loopCount) + ";"); System.out.println("sum = " + (sum) + ";"); } @Test public void testIntAdd() throws InterruptedException { // Number of threads created int threadCount = 100; // How many times other affiliated threads loop internally int loopCount = 10000600; // Control the auxiliary object of the affiliated thread; (other await threads wait for the main thread to start) CountDownLatch latch_1 = new CountDownLatch(1); // Control the auxiliary object of the main thread Object; (the main thread waits for all subsidiary threads to finish running before continuing) CountDownLatch latch_n = new CountDownLatch(threadCount); // Create and start other subsidiary threads for (int i = 0; i < threadCount; i++) { Thread thread = new IntegerThread(latch_1, latch_n, loopCount); thread.start(); } long startNano = System.nanoTime(); // Let other waiting threads start latch_1.countDown uniformly (); // Wait for other threads to finish latch_n.await(); // long endNano = System.nanoTime(); int sum = count_int; // Assert.assertNotEquals( "sum equals threadCount * loopCount, testIntAdd() test failed", sum, threadCount * loopCount); System.out.println("-------testIntAdd(); Expected the two to be unequal-- -------"); System.out.println("Time consuming: " + ((endNano - startNano) / (1000*1000))+ "ms"); System.out.println("threadCount = " + (threadCount) + ";"); System.out.println("loopCount = " + (loopCount) + ";"); System.out.println("sum = " + (sum) + ";"); } // Thread class AtomicIntegerThread extends Thread { private CountDownLatch latch = null; private CountDownLatch latchdown = null; private int loopCount; public AtomicIntegerThread(CountDownLatch latch, CountDownLatch latchdown, int loopCount) { this.latch = latch; this.latchdown = latchdown; this.loopCount = loopCount; } @Override public void run() { // Wait for signal synchronization try { this.latch. await(); } catch (InterruptedException e) { e.printStackTrace(); } // for (int i = 0; i < loopCount; i++) { counter_integer.getAndIncrement(); } // Notification is decremented by 1 latchdown.countDown(); } } // Thread class IntegerThread extends Thread { private CountDownLatch latch = null; private CountDownLatch latchdown = null; private int loopCount; public IntegerThread(CountDownLatch latch, CountDownLatch latchdown, int loopCount) { this.latch = latch; this.latchdown = latchdown; this.loopCount = loopCount; } @Override public void run() { // Wait for signal synchronization try { this.latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } // for (int i = 0; i < loopCount; i++) { count_int++; } // Notification is decremented by 1 latchdown.countDown(); } }}
The execution results on an ordinary PC are similar to the following:
---------------testAtomic(); Expected two to be equal------------------Time consuming: 85366msthreadCount = 100;loopCount = 10000600;sum = 1000060000;-----------------testIntAdd(); The two are not expected to be equal------------------Time consuming : 1406msthreadCount = 100;loopCount = 10000600;sum = 119428988;
It can be seen from this that the efficiency difference between AtomicInteger operation and int operation is about 50-80 times. Of course, int is very time-consuming. This comparison is only to provide a reference.
If it is determined to be a single-threaded execution, then int should be used; and the efficiency of int operation execution under multi-threading is quite high, and it only takes 1.5 seconds for 1 billion times;
(Assuming that the CPU is 2GHZ, dual-core and 4 threads, and the theoretical maximum is 8GHZ, there are theoretically 8 billion clock cycles per second.
One billion Java int increments takes 1.5 seconds, which is 12 billion operations. Calculated, each cycle consumes 12 CPU cycles;
Personally, I think the efficiency is good. C language should also require more than 4 clock cycles (judgment, execution of internal code, auto-increment judgment, jump)
The premise is: JVM and CPU are not radically optimized.
)
In fact, the efficiency of AtomicInteger is not low. One billion times consumes 80 seconds, and one million times is about one thousandth, 80 milliseconds.