@Test
public void testPaceController_multiThread() throws InterruptedException {
final PaceController paceController = new PaceController(1000, 160d);
final Node node = mock(Node.class); final AtomicInteger passcount = new AtomicInteger();
final AtomicInteger blockcount = new AtomicInteger(); final AtomicInteger done = new AtomicInteger();
AtomicLong lastTm = new AtomicLong(System.currentTimeMillis() / 1000);
int count = 1000;
final CountDownLatch countDown = new CountDownLatch(count); for (int i = 0; i < count; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for(int j =0; j< 10; j++) {
boolean pass = paceController.canPass(node, 1).isPass(); if (pass == true) {
passcount.incrementAndGet();
} else {
blockcount.incrementAndGet();
}
done.incrementAndGet();
long now = System.currentTimeMillis() / 1000;
if (lastTm.get() != now) {
System.out.println("pass:" + passcount.get() + ", tm:" + lastTm.get());
System.out.println("block:" + blockcount.get() + ", tm:" + lastTm.get());
System.out.println("done:" + done.get() + ", tm:" + lastTm.get());
passcount.set(0);
blockcount.set(0);
done.set(0);
}
lastTm.set(now);
}
countDown.countDown();
}
}, "Thread " + i);
thread.start();
}
countDown.await();
System.out.println("pass:" + passcount.get() + ", tm:" + lastTm.get());
System.out.println("block:" + blockcount.get() + ", tm:" + lastTm.get());
System.out.println("done:" + done.get() + ", tm:" + lastTm.get()); }
1.CountDownLatch 同步并发处理
countDown.countDown 递减为0,等待发射信号。

countDown.await()阻塞当前线程,等待调用。
2.AtomicInteger 和 volatile 的区别,CAS原子性操作。

volatile关键字很重要的两个特性:

1、保证变量在线程间可见,对volatile变量所有的写操作都能立即反应到其他线程中,换句话说,volatile变量在各个线程中是一致的(得益于java内存模型—"先行发生原则");

2、禁止指令的重排序优化;

所以volatile 并非原子性操作。

AtomicInteger非阻塞同步(原子性CAS)

同步:多线程并发访问共享数据时,保证共享数据再同一时刻只被一个或一些线程使用。

我们知道,阻塞同步和非阻塞同步都是实现线程安全的两个保障手段,非阻塞同步对于阻塞同步而言主要解决了阻塞同步中线程阻塞和唤醒带来的性能问题,那什么叫做非阻塞同步呢?在并发环境下,某个线程对共享变量先进行操作,如果没有其他线程争用共享数据那操作就成功;如果存在数据的争用冲突,那就才去补偿措施,比如不断的重试机制,直到成功为止,因为这种乐观的并发策略不需要把线程挂起,也就把这种同步操作称为非阻塞同步(操作和冲突检测具备原子性)。在硬件指令集的发展驱动下,使得 "操作和冲突检测" 这种看起来需要多次操作的行为只需要一条处理器指令便可以完成,这些指令中就包括非常著名的CAS指令(Compare-And-Swap比较并交换)。《深入理解Java虚拟机第二版.周志明》第十三章中这样描述关于CAS机制:

图取自《深入理解Java虚拟机第二版.周志明》13.2.2
所以再返回来看AtomicInteger.incrementAndGet()方法,它的时间也比较简单

/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
  return next;
}
}

incrementAndGet()方法在一个无限循环体内,不断尝试将一个比当前值大1的新值赋给自己,如果失败则说明在执行"获取-设置"操作的时已经被其它线程修改过了,于是便再次进入循环下一次操作,直到成功为止。这个便是AtomicInteger原子性的"诀窍"了,继续进源码看它的compareAndSet方法:

/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
  return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

可以看到,compareAndSet()调用的就是Unsafe.compareAndSwapInt()方法,即Unsafe类的CAS操作。

一段JAVA代码了解多线程,JUC、CAS原子性操作。的更多相关文章

  1. jsp页面:js方法里嵌套java代码(是操作数据库的),如果这个js 方法没被调用,当jsp页面被解析的时候,不管这个js方法有没有被调用这段java代码都会被执行?

    jsp页面:js方法里嵌套java代码(是操作数据库的),如果这个js 方法没被调用,当jsp页面被解析的时候,不管这个js方法有没有被调用这段java代码都会被执行? 因为在解析时最新解析的就是JA ...

  2. java 多线程12 : 无锁 实现CAS原子性操作----原子类

    由于java 多线程11:volatile关键字该文讲道可以使用不带锁的情况也就是无锁使变量变成可见,这里就理解下如何在无锁的情况对线程变量进行CAS原子性及可见性操作 我们知道,在并发的环境下,要实 ...

  3. 你觉得我的这段Java代码还有优化的空间吗?

    上周,因为要测试一个方法的在并发场景下的结果是不是符合预期,我写了一段单元测试的代码.写完之后截了个图发了一个朋友圈,很多人表示短短的几行代码,涉及到好几个知识点. 还有人给出了一些优化的建议.那么, ...

  4. linux学习之---在linux服务器上跑一段Java代码

    经常在windows上进行开发,有时候,需要在Linux环境上跑一些程序测下代码,要怎么办才好嘞? 假设你对Java常用命令和linux常用命令已经基本熟悉,就可以直接按照以下步骤来啦,默认linux ...

  5. 如何看一段JAVA代码耗了多少内存

    简单的方法,如下: Runtime r = Runtime.getRuntime();  r.gc();  long startMem = r.freememory(); // 开始时的剩余内存  你 ...

  6. 在jsp中默认写上的一段java代码表示basePath 的路径的具体的意思是什么?

    <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" ...

  7. [Java]简单计算下一段Java代码段运行了多少秒

    long startTime = System.currentTimeMillis(); ...... long endTime = System.currentTimeMillis(); logge ...

  8. JAVA多线程提高五:原子性操作类的应用

    当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...

  9. JAVA多线程学习九-原子性操作类的应用

    当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...

随机推荐

  1. 使用Eclipse远程调试

    在一般的开发中,有事因为项目需要,测试环境是在Linux下,这是如果出现异常或者bug,调试起来都是很费劲的,如果你还在为这个头疼,那就好好看接下来的总结 1,启动改程序时,不论是脚本启动,还是tom ...

  2. bzoj 1485 [HNOI2009]有趣的数列 卡特兰数

    把排好序的序列看成一对对括号,要把他们往原数列里塞,所以就是括号序合法方案数 即为卡特兰数 f(n)=Cn2nn+1 求的时候为避免除法,可以O(n)计算每个素数出现次数,最后乘起来,打完之后发现其实 ...

  3. Uber无人驾驶致命车祸翻案:6秒前已侦测到死者

    此前有消息称,今年三月 Uber 无人驾驶汽车致命车祸是软件失误导致的.现在,美国运输安全委员会的事故初步调查报告给出了不同的说法. 从图中可见,黄色线以米为单位显示,橙色线显示了地图线路的中心,紫色 ...

  4. Django 基础一(安装和启动)

    在开始跟着本文学习Django进行Web开发之前你需要有一定的python编程基础,会用一些简单的Linux系统命令.如果你对python一无所知,请先去这个网站学习一下python编程的基础 Lin ...

  5. Git----GitHub Desktop的入门及使用

    1.git和GitHub的区别: 简单回答:球和球场的关系(知乎答案,觉得简单易懂) 详细介绍:git是一个版本控制工具 github是一个用git做版本控制的项目托管平台. 2.安装本地github ...

  6. Docker 镜像之进阶篇

    笔者在<Docker 基础 : 镜像>一文中介绍了 docker 镜像的基本用法,本文我们来介绍 docker 镜像背后的技术原理. 什么是 docker 镜像 docker 镜像是一个只 ...

  7. 开源)嗨,Java,你可以生成金山词霸的二维码分享海报吗?

    As long as you can still grab a breath, you fight.只要一息尚存,就不得不战. 有那么一段时间,我特别迷恋金山词霸的每日一句分享海报.因为不仅海报上的图 ...

  8. HashMap 实现及原理

    1.为什么用HashMap? HashMap是一个散列桶(数组和链表),它存储的内容是键值对(key-value)映射HashMap采用了数组和链表的数据结构,能在查询和修改方便继承了数组的线性查找和 ...

  9. HBase的下载、安装与配置

    声明:作者原创,转载注明出处. 作者:帅气陈吃苹果 (一)安装 下载.解压: wget http://mirror.bit.edu.cn/apache/hbase/1.3.1/hbase-1.3.1- ...

  10. Python之父重回决策层,社区未来如何发展?

    春节假期结束了,大家陆续地重回到原来的生活轨道上.假期是一个很好的休息与调节的机会,同时,春节还有辞旧迎新的本意,它是新的轮回的开端. 在 Python 社区里,刚发生了一件大事,同样有开启新纪元的意 ...