(本文作者溫少,首發於部落格園,轉載請註明)
從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
}
}
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());
}
}
封裝過之後,直接使用AtomicInteger比使用InterLocked更方便,代碼也會更直觀優美!
(本文作者溫少,首發於部落格園,轉載請註明)