写了一个性能比AtomicLong性能还高的计数器
今天在学习CAS
的时候,想手写一个CAS的计数器,与JDK中的Atomic
(AtomicLong,AtomicInteger等)系列的做个比较,本想性能应该能比JDK要差一丢丢,但却加了一个让线程让出时间片的代码,性能反而更高。
由于使用java中的Unsafe
类,存在安全问题,直接使用会抛出SecurityException
异常,所以Unsage
无法直接在代码中调用,有两种方法可以解决这个问题:
增加调用的参数,让
JVM
信任,运行程序时候,增加java -Xbootclasspath:/usr/jdkxxxx/jre/lib/rt.jar:. com.mishadoff.magic.UnsafeClient
使用反射窃取字段的值,也是这篇博客使用的方式,代码如下:
1
2
3Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
为了更好的对比计数器的性能,首先定义了一个接口:
1 | public interface ICounter { |
对应的测试类:
1 | private static void testCounter(ICounter counter, String counterName) throws InterruptedException { |
分别写了各种不同的锁的版本的计数器:
线程不安全的计数器
1
2
3
4
5
6
7
8
9
10
11private long count=0;
public void increase() {
count++;
}
public long getCounter() {
return count;
}运行结果:
1
2Counter Counter计算结果: 9824109
Counter Counter计算耗时:120
synchronized
关键字计数器:1
2
3
4
5
6
7
8
9
10
11
12
13public class SyncCounter implements ICounter {
private long count=0;
public synchronized void increase() {
count++;
}
public long getCounter() {
return count;
}
}运行结果:
1
2SyncCounter Counter计算结果: 100000000
SyncCounter Counter计算耗时:4570
使用读写锁(
ReentrantLockCounter
)计数器:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class ReentrantLockCounter implements ICounter{
private long counter = 0;
private ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock();
public void increase() {
lock.lock();
counter++;
lock.unlock();
}
public long getCounter() {
return counter;
}
}运行结果:
1
2ReentrantLockCounter Counter计算结果: 100000000
ReentrantLockCounter Counter计算耗时:3734使用JDK中的
CAS
方式的计数器:1
2
3
4
5
6
7
8
9
10
11
12public class AutoCounter implements ICounter {
private AtomicLong count=new AtomicLong(0);
public void increase() {
count.incrementAndGet();
}
public long getCounter() {
return count.get();
}
}运行结果:
1
2AutoCounter Counter计算结果: 100000000
AutoCounter Counter计算耗时:2930手写
CAS
方式计数器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class RzCounter implements ICounter {
private volatile long counter = 0;
private Unsafe unsafe;
private long offset;
public RzCounter() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
offset = unsafe.objectFieldOffset(RzCounter.class.getDeclaredField("counter"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void increase() {
unsafe.getAndAddLong(this, offset, 1);
}
public long getCounter() {
return counter;
}
}运行结果:
1
2RzCounter Counter计算结果: 100000000
RzCounter Counter计算耗时:3139手写
CAS
方式计数器2:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30public class RzCounter1 implements ICounter {
private volatile long counter = 0;
private Unsafe unsafe;
private long offset;
public RzCounter1() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");//
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
offset = unsafe.objectFieldOffset(RzCounter1.class.getDeclaredField("counter"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void increase() {
long before = unsafe.getLongVolatile(this, offset);
while (!unsafe.compareAndSwapLong(this, offset, before, before + 1))
{
before = unsafe.getLongVolatile(this, offset);
Thread.yield();
}
}
public long getCounter() {
return counter;
}
}运行结果:
1
2RzCounter1 Counter计算结果: 100000000
RzCounter1 Counter计算耗时:1565
经过多次测试,性能的排序始终是经过多次测试,性能的排序始终是 CAS(RzCounter)<原生CAS<第二种CAS(RzCounter1)
,如果真是这样的话,jdk为什么不在incrementAndGet
增加一个Thread.yield()