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);act答案
// 控制主线程的辅助对象;(主线程等着所有附属线程都运行完毕再继续)
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);
// 创建并启动其他附属线程SAT答案
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没有进行激进优化。托福答案 www.daan678.com
而 AtomicInteger 效率其实也不低,10亿次消耗了80秒, 那100万次大约也就是千分之一,80毫秒的样子。
普通int值在多线程下的递增操作
时间: 2024-10-06 07:38:38
普通int值在多线程下的递增操作的相关文章
Vector 是线程安全的,是不是在多线程下操作Vector就可以不用加Synchronized
如标题一样,如果之前让我回答,我会说,是的,在多线程的环境下操作Vector,不需要加Synchronized. 但是我今天无意间看到一篇文章,我才发现我之前的想法是错误的,这篇文章的地址: http://zhangbq168.blog.163.com/blog/static/2373530520082332459511/ 我摘抄关键的一部分: Vector 比 ArrayList慢,是因为vector本身是同步的,而arraylist不是所以,没有涉及到同步的推荐用arraylist. 看jd
多线程下的进程同步(线程同步问题总结篇)
之前写过两篇关于线程同步问题的文章(一,二),这篇中将对相关话题进行总结,本文中也对.NET 4.0中新增的一些同步机制进行了介绍. 首先需要说明的是为什么需要线程功能同步.MSDN中有这样一段话很好的解释了这个问题: 当多个线程可以调用单个对象的属性和方法时,对这些调用进行同步处理是非常重要的.否则,一个线程可能会中断另一个线程正在执行的任务,使该对象处于一种无效状态. 也就说在默认无同步的情况下,任何线程都可以随时访问任何方法或字段,但一次只能有一个线程访问这些对象.另外,MSDN中也给出定
Java多线程21:多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask
CyclicBarrier 接着讲多线程下的其他组件,第一个要讲的就是CyclicBarrier.CyclicBarrier从字面理解是指循环屏障,它可以协同多个线程,让多个线程在这个屏障前等待,直到所有线程都达到了这个屏障时,再一起继续执行后面的动作.看一下CyclicBarrier的使用实例: public static class CyclicBarrierThread extends Thread { private CyclicBarrier cb; private int sleep
HashMap简单源码及多线程下的死循环
主要记录hashMap的一些基本操作源码实现原理以及多线程情况下get()操作的死循环引发原因 一.hashMap简介 1.hashMap集合的主要属性及方法 (默认初始化容量)DEFAULT_INITIAL_CAPACITY = 16 (默认最大容量)MAXIMUM_CAPACITY = 1 << 30 (默认加载因子)DEFAULT_LOAD_FACTOR = 0.75f (Entry数组)Entry[] table (Entry实例的数量)size put(K key, V value)
Java多线程20:多线程下的其他组件之CountDownLatch、Semaphore、Exchanger
前言 在多线程环境下,JDK给开发者提供了许多的组件供用户使用(主要在java.util.concurrent下),使得用户不需要再去关心在具体场景下要如何写出同时兼顾线程安全性与高效率的代码.之前讲过的线程池.BlockingQueue都是在java.util.concurrent下的组件,Timer虽然不在java.util.concurrent下,但也算是.后两篇文章将以例子的形式简单讲解一些多线程下其他组件的使用,不需要多深刻的理解,知道每个组件大致什么作用就行. 本文主要讲解的是Cou
多线程下HashMap的死循环问题
多线程下[HashMap]的问题: 1.多线程put操作后,get操作导致死循环. 2.多线程put非NULL元素后,get操作得到NULL值. 3.多线程put操作,导致元素丢失. 本次主要关注[HashMap]-死循环问题. 为何出现死循环? 大家都知道,HashMap采用链表解决Hash冲突,具体的HashMap的分析可以参考一下Java集合---HashMap源码剖析 的分析.因为是链表结构,那么就很容易形成闭合的链路,这样在循环的时候只要有线程对这个HashMap进行get操作就会产生
多线程下C#如何保证线程安全?
多线程编程相对于单线程会出现一个特有的问题,就是线程安全的问题.所谓的线程安全,就是如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的. 线程安全问题都是由全局变量及静态变量引起的. 为了保证多线程情况下,访问静态变量的安全,可以用锁机制来保证,如下所示: 1 //需要加锁的静态全局变量 2 private static bool _isOK = false; 3 //lock只能锁定一
多线程下的集合安全
在多线程内使用集合,如果未对集合做任何安全处理,就非常容易出现系统崩溃或各种错误.最近的项目里,使用的是socket通信后再改变了某个集合,结果导致系统直接崩溃,且无任何错误系统弹出. 经排查,发现问题是执行某集合后,系统就会在一定时间内退出,最后发现是使用的一个字典集合出了问题.稍微思考后,就认定了是线程安全问题.因为此集合在其它几个地方都有线程做循环读取. 下面是我模拟的一个示例,没有进行任何的安全处理: 1 class Program 2 { 3 static MyCollection m
sevlet是单线程还是多线程,在多线程下如何编写安全的servlet程序
sevlet是单线程还是多线程,在多线程下如何编写安全的servlet程序 首先明确:Servlet是单实例的,即对于同一种业务请求只有一个是实例.不同的业务请求可以通过分发来产生多个实例.其次:单实例的原因我想是因为单实例足可以处理某一个请求,就像ibatis的Querydao.UpdateDao一样都是单实例的.再次:为什么单实例足可以处理某一个请求,因为Servlet是单实例多线程的.http://hiyachen.cublog.cn [email protected]先看一段代码:pa