Java test for incrementing AtomicInteger and int values in multiple threads
- 2020-04-01 03:28:38
- OfStack
Java has designed some classes for numerical security counters with multiple threads. 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;
Here's a comparison The incrementing test of AtomicInteger and ordinary int under multi-thread, 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;
public class TestAtomic {
//Atomic Integer incrementing 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 before all tests begin
counter_integer = new AtomicInteger(0);
}
@Test
public void testAtomic() throws InterruptedException {
//Number of threads created
int threadCount = 100;
//How many times does the other dependent thread loop internally
int loopCount = 10000600;
//A secondary object that controls a dependent thread. (other await lines waiting for the main call to start)
CountDownLatch latch_1 = new CountDownLatch(1);
//Secondary objects that control the main thread; (the main thread waits until all the affiliated threads have run)
CountDownLatch latch_n = new CountDownLatch(threadCount);
//Creates and starts additional satellite 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 uniformly
latch_1.countDown();
//Wait for other threads to finish executing
latch_n.await();
//
long endNano = System.nanoTime();
int sum = counter_integer.get();
//
Assert.assertEquals("sum Is not equal to threadCount * loopCount, Test to fail ",
sum, threadCount * loopCount);
System.out.println("--------testAtomic(); They are 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 does the other dependent thread loop internally
int loopCount = 10000600;
//A secondary object that controls a dependent thread. (other await lines waiting for the main call to start)
CountDownLatch latch_1 = new CountDownLatch(1);
//Secondary objects that control the main thread; (the main thread waits until all the affiliated threads have run)
CountDownLatch latch_n = new CountDownLatch(threadCount);
//Creates and starts additional satellite 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 uniformly
latch_1.countDown();
//Wait for other threads to finish executing
latch_n.await();
//
long endNano = System.nanoTime();
int sum = count_int;
//
Assert.assertNotEquals(
"sum Is equal to the threadCount * loopCount,testIntAdd() Test to fail ",
sum, threadCount * loopCount);
System.out.println("-------testIntAdd(); The expectation is not the same ---------");
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 signal synchronization
try {
this.latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//
for (int i = 0; i < loopCount; i++) {
counter_integer.getAndIncrement();
}
//Notice decrement 1 time
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 signal synchronization
try {
this.latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//
for (int i = 0; i < loopCount; i++) {
count_int++;
}
//Notice decrement 1 time
latchdown.countDown();
}
}
}
The execution results of ordinary PC are similar to the following:
--------------testAtomic(); They are expected to be equal -------------------
Time consuming : 85366ms
threadCount = 100;
loopCount = 10000600;
sum = 1000060000;
--------------testIntAdd(); The expectation is not the same -------------------
Time consuming : 1406ms
threadCount = 100;
loopCount = 10000600;
sum = 119428988;
As you can see, the efficiency difference between the AtomicInteger operation and the int operation is roughly 50-80 times. Of course,int is very time consuming, and this comparison only provides a reference.
If single thread execution is determined, int should be used; The efficiency of int in multi-threaded operation is quite high, it only takes 1.5 seconds to execute 1 billion operations.
(if the CPU is 2GHZ, dual-core 4 threads, and the theoretical maximum is 8GHZ, then there are theoretically 8 billion clock cycles per second.
One billion Java int increments consume 1.5 seconds, or 12 billion operations, which adds up to 12 CPU cycles per cycle.
Personally, I think the efficiency is good. C language should also need more than 4 clock cycles (judgment, internal code execution, self-increment judgment, jump).
The premise is that the JVM and CPU are not being aggressively optimized.
)
And AtomicInteger is not that inefficient, a billion takes 80 seconds, so a million takes about a thousandth of that,80 milliseconds.