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.


Related articles: