- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想使用 CAS 来改进我的代码,但我怀疑它能否获得更好的性能,所以我做了一个测试。这是测试代码,这个jmh代码靠谱吗?
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.SampleTime)
@Warmup(iterations = 5)
@Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS)
@Threads(20)
@Fork(1)
@State(Scope.Benchmark)
public class CASBench {
private int id=24;
private static Object[] lockObj;
private static AtomicReference<Integer>[] locks;
static {
lockObj = new Object[100];
for (int i = 0; i < lockObj.length; i++) {
lockObj[i] = new Object();
}
locks = new AtomicReference[100];
for (int i = 0; i < locks.length; i++) {
locks[i] = new AtomicReference<Integer>(null);
}
}
@Benchmark
public void sync() throws Exception {
int index = id % 100;
synchronized (lockObj[index]) {
test();
}
}
@Benchmark
public void cas() throws Exception {
AtomicReference<Integer> lock = locks[id % 100];
while (!lock.compareAndSet(null, id)) {
}
test();
lock.compareAndSet(id, null);
}
public void test() throws Exception {
int sum=0;
for(int i=0;i<100;i++){
sum += i;
}
}
}
我得到了 jmh 测试结果:
Benchmark Mode Cnt Score Error Units
CASBench.cas sample 25866638 0.014 ± 0.001 ms/op
CASBench.cas:cas·p0.00 sample ≈ 10⁻⁶ ms/op
CASBench.cas:cas·p0.50 sample ≈ 10⁻⁴ ms/op
CASBench.cas:cas·p0.90 sample 0.001 ms/op
CASBench.cas:cas·p0.95 sample 0.001 ms/op
CASBench.cas:cas·p0.99 sample 0.001 ms/op
CASBench.cas:cas·p0.999 sample 0.002 ms/op
CASBench.cas:cas·p0.9999 sample 38.164 ms/op
CASBench.cas:cas·p1.00 sample 813.695 ms/op
CASBench.sync sample 26257757 0.011 ± 0.001 ms/op
CASBench.sync:sync·p0.00 sample ≈ 10⁻⁶ ms/op
CASBench.sync:sync·p0.50 sample ≈ 10⁻⁴ ms/op
CASBench.sync:sync·p0.90 sample 0.001 ms/op
CASBench.sync:sync·p0.95 sample 0.001 ms/op
CASBench.sync:sync·p0.99 sample 0.005 ms/op
CASBench.sync:sync·p0.999 sample 1.883 ms/op
CASBench.sync:sync·p0.9999 sample 15.270 ms/op
CASBench.sync:sync·p1.00 sample 45.810 ms/op
我能得出这个结论吗,在这种情况下synchronized更好?
最佳答案
据我所知,您的测试确实不正确。首先,您的基准测试应该返回一个值,如样本 here 中指定的那样或使用 BlackHoles
。
有两种方法可以对此进行测试,第一种是在有争用
的情况下,另一种是没有。
让我们看看在争用下会发生什么,它更容易掌握:
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class Contention {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.jvmArgs("-ea")
.shouldFailOnError(true)
.include(Contention.class.getSimpleName()).build();
new Runner(opt).run();
}
private AtomicInteger atomic;
private Object lock = new Object();
private int i = 0;
@Setup
public void setUp() {
atomic = new AtomicInteger(0);
}
@Fork(1)
@Threads(10)
@Benchmark
public int incrementAtomic() {
return atomic.incrementAndGet();
}
@Fork(1)
@Threads(10)
@Benchmark
public int incrementSync() {
synchronized (lock) {
++i;
}
return i;
}
}
代码应该是不言自明的;在这里稍微解释一下:
State(Scope.Benchmark)
如果您将其更改为:State(Scope.Thread)
每个 线程将获得它的自己的锁,因此这段代码将是被 biased-locking
扭曲。这意味着如果您将使用以下代码运行此代码:
State(Scope.Thread)
您的输出将非常相同。像这样:
Benchmark Mode Cnt Score Error Units
casVSsynchronized.Contention.incrementAtomic avgt 5 36.526 ± 6.548 ns/op
casVSsynchronized.Contention.incrementSync avgt 5 23.655 ± 3.393 ns/op
运行它:
@State(Scope.Benchmark)
显示完全不同的图片。 在竞争中,CAS 表现得更好,正如您从结果中看到的那样:
Benchmark Mode Cnt Score Error Units
casVSsynchronized.Contention.incrementAtomic avgt 5 212.997 ± 42.902 ns/op
casVSsynchronized.Contention.incrementSync avgt 5 457.896 ± 46.811 ns/op
比我有一些更复杂的测试(这可能需要来自 jmh 开发人员的更多限制性审查):
import java.util.concurrent.TimeUnit;
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
public class CASSync {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.jvmArgs("-ea")
.shouldFailOnError(true)
.include(CASSync.class.getSimpleName()).build();
new Runner(opt).run();
}
@State(Scope.Thread)
static public class AtomicHolder {
AtomicInteger i = null;
@Setup(Level.Invocation)
public void setUp() {
i = new AtomicInteger(0);
}
@TearDown(Level.Invocation)
public void tearDown() {
assert i.intValue() == 1;
i = null;
}
}
@State(Scope.Thread)
static public class SyncHolder {
int i = 0;
Object lock = null;
@Setup(Level.Invocation)
public void setUp() {
lock = new Object();
i = 0;
}
@TearDown(Level.Invocation)
public void tearDown() {
assert i == 1;
lock = null;
}
}
@Benchmark
@Fork(1)
public boolean cas(AtomicHolder holder) {
return holder.i.compareAndSet(0, 1);
}
@Benchmark
@Fork(1)
public boolean sync(SyncHolder holder) {
synchronized (holder.lock) {
++holder.i;
}
return holder.i == 1;
}
}
这个测试完全没有竞争的情况(就像第一个),但是这次摆脱了biased-locking
。结果:
Benchmark Mode Cnt Score Error Units
casVSsynchronized.CASSync.cas avgt 5 44.003 ± 1.343 ns/op
casVSsynchronized.CASSync.sync avgt 5 50.744 ± 1.370 ns/o
我的结论:对于竞争环境,CAS 更好。对于其余的,这是值得商bat的。
关于java - 如何测试同步之间compareAndSet的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43960763/
Java 通过其原子类公开 CAS 操作,例如 boolean compareAndSet(expected,update) JavaDocs指定 compareAndSet 操作的内存效果如下: c
假设您有以下类(class) public class AccessStatistics { private final int noPages, noErrors; public Acces
正在学习并发编程类(class)。 举个例子 final class Counter { private AtomicInteger value; public lon
我想知道原子类中 set() 和 compareAndSet() 的区别。 set() 方法是否也保证了原子过程?例如这段代码: public class sampleAtomic{ priv
今天我在采访中被问到下一个问题:“如果您在处理器不支持 CAS 操作的机器上调用 AtomicLong 的 compareAndSet 方法,会发生什么情况”。 能否请您帮我解决这个问题,并在可能的情
我正在实现一个简单的缓存,并将缓存存储为 AtomicReference。 private AtomicReference> cacheData; 应该从数据库表中(延迟地)填充缓存对象。 我提供了一
我正在试验 java.util.concurrent 并试图找出如何正确使用 AtomicReference.compareAndSet 来管理对单个共享状态单元的并发访问。 特别是:compareA
spring-data-redis 模块包含 RedisAtomicLong 类。 在这个类中你可以看到 public boolean compareAndSet(long expect, long
From the Java AtomicReferenceFieldUpdater docs : Note that the guarantees of the compareAndSet metho
源码是一样的。 public final boolean compareAndSet(V expect, V update) { return unsafe.compareAndSwapObj
在阅读 Java 中 java.util.Random 类的文档时,我偶然发现了 next 方法中的一些东西,我无法完全理解。 protected int next(int bits) { l
Java 的 AtomicInteger 提供 public final boolean compareAndSet(int expect, int update) .如果返回false,我想知道比较
线程标题应该是不言自明的......我对 AtomicBoolean 类的以下方法的规范有点困惑: java.util.concurrent.atomic.AtomicBoolean#compareA
我希望将 AtomicLong 中的当前 timestamp 与 currentTimeMS 进行比较,以便我知道是否已经过去了一段时间,如果是,则只有一个单线程将进入一个代码块,但据我所知,comp
来自AtomicLong的源代码: public final boolean compareAndSet(long expect, long update) { return
因为 Atomic 意味着线程安全。当 .set() 本身在 Java 中是原子和线程安全的时,我们什么时候使用 compareAndSet? 举例来说,我想自动设置一个变量,这样每个其他线程都可以看
static boolean unsynchronizedSetter(Date expected){ Date newDate = new Date(); AtomicReferen
VarHandle 显示以下错误 - Exception in thread "main" java.lang.NoSuchMethodError: VarHandle.compareAndSet(V
我正在实现一个请求实例的 FIFO 队列(为速度而预先分配的请求对象),并开始使用 add 方法上的“同步”关键字。该方法很短(检查固定大小缓冲区中是否有空间,然后将值添加到数组)。使用visualV
我想知道调用之间是否有任何区别(或可能的副作用): AtomicBoolean.set(true) 和 AtomicBoolean.compareAndset(false, true) AtomicB
我是一名优秀的程序员,十分优秀!