vs2008如何新建网站,网站建设实践,如何建一个公司的网站,wordpress如何添加菜单链接我们认为#xff0c;由于思维定式原子变量总是比同步运行的速度更快#xff0c;我想是这样也已经#xff0c;直到实现了ID在第一次测试过程生成器不具有在这样一个迷迷糊糊的东西。测试代码#xff1a; import java.util.ArrayList;
import java.util.List;
import java.ut… 我们认为由于思维定式原子变量总是比同步运行的速度更快我想是这样也已经直到实现了ID在第一次测试过程生成器不具有在这样一个迷迷糊糊的东西。 测试代码 import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;public class ConcurrentAdder {private static final AtomicInteger ATOMIC_INTEGER new AtomicInteger(0);private static int I 0;private static final Object o new Object();private static volatile long start;public static void main(final String[] args) {//每一个线程运行多少次累加int round 10000000;//线程个个数int threadn 20;start System.currentTimeMillis();atomicAdder(threadn, round);//syncAdder(threadn, round);}static void atomicAdder(int threadn, int addTimes) {int stop threadn * addTimes;ListThread list new ArrayListThread();for (int i 0; i threadn; i) {list.add(startAtomic(addTimes, stop));}for (Thread each : list) {each.start();}}static Thread startAtomic(final int addTimes, final int stop) {Thread ret new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i addTimes; i) {int v ATOMIC_INTEGER.incrementAndGet();if (stop v) {System.out.println(value: v);System.out.println(elapsed(ms): (System.currentTimeMillis() - start));System.exit(1);}}}});ret.setDaemon(false);return ret;}static void syncAdder(int threadn, int addTimes) {int stop threadn * addTimes;ListThread list new ArrayListThread();for (int i 0; i threadn; i) {list.add(startSync(addTimes, stop));}for (Thread each : list) {each.start();}}static Thread startSync(final int addTimes, final int stop) {Thread ret new Thread(new Runnable() {Overridepublic void run() {for (int i 0; i addTimes; i) {synchronized (o) {I;if (stop I) {System.out.println(value: I);System.out.println(elapsed(ms): (System.currentTimeMillis() - start));System.exit(1);}}}}});ret.setDaemon(false);return ret;}
}
这是一个非常easy的累加器N个线程并发累加每一个线程累加R次。 分别凝视 atomicAdder(threadn, round);//原子变量累加
syncAdder(threadn, round);//同步累加中的一行运行还有一行 笔者机器的配置i5-2520M 2.5G 四核 N20 R10000000 结果 原子累加15344 ms 同步累加10647 ms 问题出来了为什么同步累加会比原子累加要快50%左右 我们知道java加锁的过程是内置sync和显式lock类似要加锁的线程检查下锁是否被占用。假设被占用则增加到目标锁的等待队列。假设没有则。加锁。 这里我们每一个线程获取到锁累加之后就立刻又去获取锁这时其它线程还没有被唤醒。锁又被当前线程拿到了。这也就是非公平锁可能造成的饥饿问题。 可是这一个原因不能解释50%的性能提升理论上。在一个绝对时间。总有一个线程累加成功那么两种累加器的耗时应该近似才对。 那么是有什么提升了同步累加的性能。或者是什么减少了原子累加的性能 接下来笔者分别perf了一下两种累加器的运行过程 第一次运行的是原子累加器第二次运行的同步累加器。 wxfpc:/data$ perf stat -e cs -e L1-dcache-load-misses java ConcurrentAdder
value:100000000
elapsed(ms):8580Performance counter stats for java ConcurrentAdder 1 100 1000000:21,841 cs 233,140,754 L1-dcache-load-misses 8.633037253 seconds time elapsed
wxfpc:/data$ perf stat -e cs -e L1-dcache-load-misses java ConcurrentAdder
value:100000000
elapsed(ms):5749Performance counter stats for java ConcurrentAdder 2 100 1000000:55,522 cs 28,160,673 L1-dcache-load-misses 5.811499179 seconds time elapsed我们能够看出同步累加的上下文切换是要比原子累加多。这个能够理解加锁本身就会添加线程的切换。 再看原子累加器的L1缓存失效比同步累加器高一个数量级 笔者茅塞顿开原子操作会导致缓存一致性问题。从而导致频繁的缓存行失效。缓存一致性协议MESI见http://en.wikipedia.org/wiki/MESI_protocol 可是这时同步累加器在一个CPU周期内重复的获取锁操作。缓存并没有失效。 再把每次累加的线程ID输出来会发现。原子累加的线程分布要分散非常多。 回到问题上来。为什么我们会一直觉得原子操作比加锁要快呢文中的样例是非常特别非常特别的正常业务场景下我们累加过后要经过非常多业务代码逻辑才会再次去累加这里已经跨过非常多个CPU时间片了。从而同步累加器非常难一直获取到锁。这中情况下同步累加器即会有等待加锁的性能损失还会有缓存一致性带来的性能损失。所以在一般的情况下同步累加器会慢非常多。 版权声明本文博客原创文章。博客未经同意不得转载。 转载于:https://www.cnblogs.com/hrhguanli/p/4740290.html