public static void main(String[] args) throws InterruptedException {
Thread[] ts = new Thread[10];
for (int k = 0; k < 10; k++) {
ts[k] = new Thread(new AddThread());
}
for (int k = 0; k < 10; k++) {
ts[k].start();
}
for (int k = 0; k < 10; k++) {
ts[k].join();
}
System.out.println(i);
}
}
Unsafe类是在sun.misc包下, 可以用于一些非安全的操作,比如:
根据偏移量设置值, 线程park(), 底层的CAS操作等等.
1 // 获取类实例中变量的偏移量
2 valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
3 // 基于偏移量对值进行操作
4 unsafe.compareAndSwapInt(this, valueOffset, expect, update);
主要接口
// 获得给定对象偏移量上的int值
public native int getInt(Object o, long offset);
// 设置给定对象偏移量上的int值
public native void putInt(Object o, long offset, int x);
// 获得字段在对象中的偏移量
public native long objectFieldOffset(Field f);
// 设置给定对象的int值,使用volatile语义
public native void putIntVolatile(Object o, long offset, int x);
// 获得给定对象对象的int值,使用volatile语义
public native int getIntVolatile(Object o, long offset);
// 和putIntVolatile()一样,但是它要求被操作字段就是volatile类型的
public native void putOrderedInt(Object o, long offset, int x);
与AtomicInteger类似, 只是里面封装了一个对象, 而不是int, 对引用进行修改
主要接口
1 get()
2 set(V)
3 compareAndSet()
4 getAndSet(V)
Demo
使用10个线程, 同时尝试修改AtomicReference中的String, 最终只有一个线程可以成功.
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceTest {
public final static AtomicReference<String> attxnicStr = new AtomicReference<String>("abc");
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
try {
Thread.sleep(Math.abs((int) (Math.random() * 100)));
} catch (InterruptedException e) {
e.printStackTrace();
}
if (attxnicStr.compareAndSet("abc", "def")) {
System.out.println("Thread:" + Thread.currentThread().getId() + " change value to " + attxnicStr.get());
} else {
System.out.println("Thread:" + Thread.currentThread().getId() + " change failed!");
}
}
}.start();
}
}
}
也是封装了一个引用, 主要解决ABA问题.
ABA问题
线程一准备用CAS将变量的值由A替换为B, 在此之前线程二将变量的值由A替换为C, 线程三又将C替换为A, 然后线程一执行CAS时发现变量的值仍然为A, 所以线程一CAS成功.
主要接口
// 比较设置 参数依次为:期望值 写入新值 期望时间戳 新时间戳
public boolean compareAndSet(V expectedReference,V newReference,int expectedStamp,int newStamp)
// 获得当前对象引用
public V getReference()
// 获得当前时间戳
public int getStamp()
// 设置当前对象引用和时间戳
public void set(V newReference, int newStamp)
源码分析
// 内部封装了一个Pair对象, 每次对对象操作的时候, stamp + 1
private static class Pair<T> {
final T reference;
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;