java unsafe compareandswap 并发

使用Unsafe.compareAndSwapXXX方法来实现并发,它是原子的并且可以用来实现高性能的数据结构。

下面是一个例子,被很多线程使用的共享对象的值的问题。

Counter

1
2
3
4
interface {
void increment();
long getCounter();
}

Counter 实例

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
static class CASCounter implements {
private volatile long counter = 0;
private Unsafe unsafe;
private long offset;
public CASCounter() throws Exception {
unsafe = getUnsafe();
offset = unsafe.objectFieldOffset(CASCounter.class.getDeclaredField("counter"));
}
public void increment() {
long before = counter;
while (!unsafe.compareAndSwapLong(this, offset, before, before + 1)) {
before = counter;
}
}
public long getCounter() {
return counter;
}
}
static class AtomicCounter implements {
AtomicLong counter = new AtomicLong(0);
public void increment() {
counter.incrementAndGet();
}
public long getCounter() {
return counter.get();
}
}
static class LockCounter implements {
private volatile long counter = 0;
private WriteLock lock = new ReentrantReadWriteLock().writeLock();
public void increment() {
lock.lock();
counter++;
lock.unlock();
}
@Override
public long getCounter() {
return counter;
}
}
static class SyncCounter implements {
private volatile long counter = 0;
@Override
public synchronized void increment() {
counter++;
}
@Override
public long getCounter() {
return counter;
}
}
static class StupidCounter implements Counter {
private volatile long counter = 0;
@Override
public void increment() {
counter++;
}
@Override
public long getCounter() {
return counter;
}
}
static class CounterClient implements Runnable {
private volatile Counter c;
private int num;
public CounterClient(Counter c, int num) {
this.c = c;
this.num = num;
}
@Override
public void run() {
for (int i = 0; i < num; i++) {
c.increment();
}
}
}

Test

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
30
31
32
public static void main(String[] args) throws Exception {
int NUM_OF_THREADS = 200;
int NUM_OF_INCREMENTS = 100000;
ExecutorService service = Executors.newFixedThreadPool(NUM_OF_THREADS);
Counter counter = null;
counter = new StupidCounter();
// Counter result: 2087134
// Time passed in ms:469
counter = new SyncCounter();
// Counter result: 10000000
// Time passed in ms:1407
counter = new LockCounter();
// Counter result: 10000000
// Time passed in ms:1259
counter = new AtomicCounter();
// Counter result: 10000000
// Time passed in ms:3361
counter = new CASCounter();
// Counter result: 10000000
// Time passed in ms:3939
long before = System.currentTimeMillis();
for (int i = 0; i < NUM_OF_THREADS; i++) {
service.submit(new CounterClient(counter, NUM_OF_INCREMENTS));
}
service.shutdown();
service.awaitTermination(1, TimeUnit.MINUTES);
long after = System.currentTimeMillis();
System.out.println("Counter result: " + counter.getCounter());
System.out.println("Time passed in ms:" + (after - before));
}

参考

Link