zoukankan      html  css  js  c++  java
  • 测试AtomicInteger与普通int值在多线程下的递增操作

    日期: 2014年6月10日

    作者: 铁锚

    Java针对多线程下的数值安全计数器设计了一些类,这些类叫做原子类,其中一部分如下:

    java.util.concurrent.atomic.AtomicBoolean;
    java.util.concurrent.atomic.AtomicInteger;
    java.util.concurrent.atomic.AtomicLong;
    java.util.concurrent.atomic.AtomicReference;
    下面是一个对比  AtomicInteger 与 普通 int 值在多线程下的递增测试,使用的是 junit4;

    完整代码:

    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;
    
    /**
     * 测试AtomicInteger与普通int值在多线程下的递增操作
     */
    public class TestAtomic {
    
    	// 原子Integer递增对象
    	public static AtomicInteger counter_integer;// = new AtomicInteger(0);
    	// 一个int类型的变量
    	public static int count_int = 0;
    
    	@Before
    	public void setUp() {
    		// 所有测试开始之前执行初始设置工作
    		counter_integer = new AtomicInteger(0);
    	}
    
    	@Test
    	public void testAtomic() throws InterruptedException {
    		// 创建的线程数量
    		int threadCount = 100;
    		// 其他附属线程内部循环多少次
    		int loopCount = 10000600;
    		// 控制附属线程的辅助对象;(其他await的线程先等着主线程喊开始)
    		CountDownLatch latch_1 = new CountDownLatch(1);
    		// 控制主线程的辅助对象;(主线程等着所有附属线程都运行完毕再继续)
    		CountDownLatch latch_n = new CountDownLatch(threadCount);
    		// 创建并启动其他附属线程
    		for (int i = 0; i < threadCount; i++) {
    			Thread thread = new AtomicIntegerThread(latch_1, latch_n, loopCount);
    			thread.start();
    		}
    		long startNano = System.nanoTime();
    		// 让其他等待的线程统一开始
    		latch_1.countDown();
    		// 等待其他线程执行完
    		latch_n.await();
    		//
    
    		long endNano = System.nanoTime();
    		int sum = counter_integer.get();
    		//
    		Assert.assertEquals("sum 不等于 threadCount * loopCount,测试失败",
    				sum, threadCount * loopCount);
    		System.out.println("--------testAtomic(); 预期两者相等------------");
    		System.out.println("耗时: " + ((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 {
    		// 创建的线程数量
    		int threadCount = 100;
    		// 其他附属线程内部循环多少次
    		int loopCount = 10000600;
    		// 控制附属线程的辅助对象;(其他await的线程先等着主线程喊开始)
    		CountDownLatch latch_1 = new CountDownLatch(1);
    		// 控制主线程的辅助对象;(主线程等着所有附属线程都运行完毕再继续)
    		CountDownLatch latch_n = new CountDownLatch(threadCount);
    		// 创建并启动其他附属线程
    		for (int i = 0; i < threadCount; i++) {
    			Thread thread = new IntegerThread(latch_1, latch_n, loopCount);
    			thread.start();
    		}
    		long startNano = System.nanoTime();
    		// 让其他等待的线程统一开始
    		latch_1.countDown();
    		// 等待其他线程执行完
    		latch_n.await();
    		//
    		long endNano = System.nanoTime();
    		int sum = count_int;
    		//
    		Assert.assertNotEquals(
    				"sum 等于 threadCount * loopCount,testIntAdd()测试失败", 
    				sum, threadCount * loopCount);
    		System.out.println("-------testIntAdd(); 预期两者不相等---------");
    		System.out.println("耗时: " + ((endNano - startNano) / (1000*1000))+ "ms");
    		System.out.println("threadCount = " + (threadCount) + ";");
    		System.out.println("loopCount = " + (loopCount) + ";");
    		System.out.println("sum = " + (sum) + ";");
    	}
    
    	// 线程
    	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() {
    			// 等待信号同步
    			try {
    				this.latch.await();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			//
    			for (int i = 0; i < loopCount; i++) {
    				counter_integer.getAndIncrement();
    			}
    			// 通知递减1次
    			latchdown.countDown();
    		}
    	}
    
    	// 线程
    	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() {
    			// 等待信号同步
    			try {
    				this.latch.await();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			//
    			for (int i = 0; i < loopCount; i++) {
    				count_int++;
    			}
    			// 通知递减1次
    			latchdown.countDown();
    		}
    	}
    }

    普通PC机上的执行结果类似如下:

    --------------testAtomic(); 预期两者相等-------------------
    耗时: 85366ms
    threadCount = 100;
    loopCount = 10000600;
    sum = 1000060000;
    --------------testIntAdd(); 预期两者不相等-------------------
    耗时: 1406ms
    threadCount = 100;
    loopCount = 10000600;
    sum = 119428988;

    从中可以看出, AtomicInteger操作 与 int操作的效率大致相差在50-80倍上下,当然,int很不消耗时间,这个对比只是提供一个参照。

    如果确定是单线程执行,那应该使用 int; 而int在多线程下的操作执行的效率还是蛮高的, 10亿次只花了1.5秒钟;

     (假设CPU是 2GHZ,双核4线程,理论最大8GHZ,则每秒理论上有80亿个时钟周期, 

    10亿次Java的int增加消耗了1.5秒,即 120亿次运算, 算下来每次循环消耗CPU周期 12个; 

    个人觉得效率不错, C 语言也应该需要4个以上的时钟周期(判断,执行内部代码,自增判断,跳转)

    前提是: JVM和CPU没有进行激进优化.

    )

    而 AtomicInteger 效率其实也不低,10亿次消耗了80秒, 那100万次大约也就是千分之一,80毫秒的样子.

  • 相关阅读:
    HashMap按键排序和按值排序
    LeetCode 91. Decode Ways
    LeetCode 459. Repeated Substring Pattern
    JVM
    LeetCode 385. Mini Parse
    LeetCode 319. Bulb Switcher
    LeetCode 343. Integer Break
    LeetCode 397. Integer Replacement
    LeetCode 3. Longest Substring Without Repeating Characters
    linux-网络数据包抓取-tcpdump
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467010.html
Copyright © 2011-2022 走看看