抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

JUC简介

在 Java 5.0 提供了 java.util.concurrent (简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的 Collection 实现等。

在JUC并发包中包含有AtomicInteger,AtomicLong,AtomicBoolean等基于CAS操作的原子操作类。他们原理相似,下面讲解AtomicLong类。它可以原子性递增或递减,内部通过Unsafe来实现。

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
public class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L;

// 获得Unsafe实例
private static final Unsafe unsafe = Unsafe.getUnsafe();

//获得long值偏移量
private static final long valueOffset;

//判断JVM是否支持Long类型的无锁CAS操作
static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

//本地方法。。
private static native boolean VMSupportsCS8();

//静态代码块
static {
try {
获得偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}

//实际值
private volatile long value;

public AtomicLong(long initialValue) {
value = initialValue;
}

public AtomicLong() {
}
}

Unsafe类

在jdk中提供了Unsafe类来实现CAS操作,该类中的所有方法都是本地方法(Native),下面是Unsafe几个重要方法

long object FieldOffset(Field field)方法, 负责获得指定变量在所属类中的内存偏移量,该偏移量只能在Unsafe方法中访问指定函数才能使用

long native getLongVolatile(Object obj,long offset)方法,负责获得对象obj中指定偏移量offset的变量所对应的值

AtomicLong

递增递减操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//获得递增后的值
public final long incrementAndGet() {
return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}

//获得递减后的值
public final long decrementAndGet() {
return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
}
//获得递增前的值
public final long getAndIncrement() {
return unsafe.getAndAddLong(this, valueOffset, 1L);
}
获得递减前的值
public final long getAndDecrement() {
return unsafe.getAndAddLong(this, valueOffset, -1L);
}

上面的递增递减操作都是调用了Unsafe的getAndAddLong()方法来实现的,该函数时原子性操作。

1
2
3
4
5
6
7
8
9
10
11
12
//参数一代表AtomicLong实例的引用,
//参数二代表AtomicLong的value变量的偏移量
//参数三代表要改变的值
public final long getAndAddLong(Object var1, long var2, long var4) {
long var6;
do {
var6 = this.getLongVolatile(var1, var2);//获得初始值
//如果获得的初始值不相等则继续循环直到相等
} while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

return var6;
}

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class TestAtomic {
public static void main(String[] args) throws InterruptedException {
for (int i=0;i<10;i++){
Thread thread=new Thread(new CountThread(),"线程"+i);
thread.start();
thread.join();
}
System.out.println(CountThread.value);
}
public static class CountThread implements Runnable{

public static AtomicLong value=new AtomicLong();
@Override
public void run() {
for (int i=0;i<1000;i++){
value.incrementAndGet();
}
}
}
}

总结

在没有原子类的情况下,要实现多线程计数器需要同步措施,例如使用synchronized关键字,但这会大大影响性能,而这些Atomic原子类实现了CAS非堵塞算法,提升了性能。不过在高并发的情况下还是会影响性能,在JDK8中提供了在高并发性能更好的LongAdder类,下次再来写了。