从JDK 1.5开始,util.concurrent包提供了Atomic类型,包括AtomicInteger、AtomicLong、AtomicBoolean、AtomicReference、AtomicFieldUpdate等,这些类在并发编程中大有作用。
我原先以为JDK中的Atomic在Windows下实现是调用<windows.h>中InterLockedXXX系列函数实现的,但后来查看了JDK的源码,发现和原先想像中的不一样。JVM的实现中,封装了一个Atomic的类,然后不同的操作系统有不同的实现,例如,在JDK 1.6源码hotspot\src\os_cpu\win32_i486\vm\atomic_win32_i486.inline.hpp文件中:
inline jlong Atomic::cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value) {
int mp = os::is_MP();
jint ex_lo = (jint)exchange_value;
jint ex_hi = *( ((jint*)&exchange_value) + 1 );
jint cmp_lo = (jint)compare_value;
jint cmp_hi = *( ((jint*)&compare_value) + 1 );
__asm {
push ebx
push edi
mov eax, cmp_lo
mov edx, cmp_hi
mov edi, dest
mov ebx, ex_lo
mov ecx, ex_hi
LOCK_IF_MP(mp)
cmpxchg8b qword ptr [edi]
pop edi
pop ebx
}
}
int mp = os::is_MP();
jint ex_lo = (jint)exchange_value;
jint ex_hi = *( ((jint*)&exchange_value) + 1 );
jint cmp_lo = (jint)compare_value;
jint cmp_hi = *( ((jint*)&compare_value) + 1 );
__asm {
push ebx
push edi
mov eax, cmp_lo
mov edx, cmp_hi
mov edi, dest
mov ebx, ex_lo
mov ecx, ex_hi
LOCK_IF_MP(mp)
cmpxchg8b qword ptr [edi]
pop edi
pop ebx
}
}
C#也提供了同样的能力,System.Threading.Interlocked封装了<windows.h>中的 InterlockedXXX系列函数,可以实现同样的功能,但是直接使用InterLocked没有象Java中的Atomic系列对象方便。
了解清楚Java中的AtomicXXX和.NET中InterLockedXXX系列函数之后,把Java的AtomicXXX系列对象在C#上重新实现一遍是很容易的事情。例如实现AtomicInteger:
public class AtomicInteger
{
private int value;
public AtomicInteger(int initialValue)
{
value = initialValue;
}
public AtomicInteger()
: this(0)
{
}
public int Get()
{
return value;
}
public void Set(int newValue)
{
value = newValue;
}
public int GetAndSet(int newValue)
{
for (; ; )
{
int current = Get();
if (CompareAndSet(current, newValue))
return current;
}
}
public bool CompareAndSet(int expect, int update)
{
return Interlocked.CompareExchange(ref value, update, expect) == expect;
}
public int GetAndIncrement()
{
for (; ; )
{
int current = Get();
int next = current + 1;
if (CompareAndSet(current, next))
return current;
}
}
public int GetAndDecrement()
{
for (; ; )
{
int current = Get();
int next = current - 1;
if (CompareAndSet(current, next))
return current;
}
}
public int GetAndAdd(int delta)
{
for (; ; )
{
int current = Get();
int next = current + delta;
if (CompareAndSet(current, next))
return current;
}
}
public int IncrementAndGet()
{
for (; ; )
{
int current = Get();
int next = current + 1;
if (CompareAndSet(current, next))
return next;
}
}
public int DecrementAndGet()
{
for (; ; )
{
int current = Get();
int next = current - 1;
if (CompareAndSet(current, next))
return next;
}
}
public int AddAndGet(int delta)
{
for (; ; )
{
int current = Get();
int next = current + delta;
if (CompareAndSet(current, next))
return next;
}
}
public override String ToString()
{
return Convert.ToString(Get());
}
}
{
private int value;
public AtomicInteger(int initialValue)
{
value = initialValue;
}
public AtomicInteger()
: this(0)
{
}
public int Get()
{
return value;
}
public void Set(int newValue)
{
value = newValue;
}
public int GetAndSet(int newValue)
{
for (; ; )
{
int current = Get();
if (CompareAndSet(current, newValue))
return current;
}
}
public bool CompareAndSet(int expect, int update)
{
return Interlocked.CompareExchange(ref value, update, expect) == expect;
}
public int GetAndIncrement()
{
for (; ; )
{
int current = Get();
int next = current + 1;
if (CompareAndSet(current, next))
return current;
}
}
public int GetAndDecrement()
{
for (; ; )
{
int current = Get();
int next = current - 1;
if (CompareAndSet(current, next))
return current;
}
}
public int GetAndAdd(int delta)
{
for (; ; )
{
int current = Get();
int next = current + delta;
if (CompareAndSet(current, next))
return current;
}
}
public int IncrementAndGet()
{
for (; ; )
{
int current = Get();
int next = current + 1;
if (CompareAndSet(current, next))
return next;
}
}
public int DecrementAndGet()
{
for (; ; )
{
int current = Get();
int next = current - 1;
if (CompareAndSet(current, next))
return next;
}
}
public int AddAndGet(int delta)
{
for (; ; )
{
int current = Get();
int next = current + delta;
if (CompareAndSet(current, next))
return next;
}
}
public override String ToString()
{
return Convert.ToString(Get());
}
}
封装过之后,直接使用AtomicInteger比使用InterLocked更方便,代码也会更直观优美!
(本文作者温少,首发于博客园,转载请注明)