推荐:Java并发编程汇总
Java并发编程一引用类型、升级类型原子类初使用加源码分析
首先我们来看一看有哪些原子类。
现在我们来看看该如何去使用这些引用类型、升级类型原子类吧。
之前已经介绍过基本类型、数组类型原子类和累加器的使用了,讲过的原理这里就不会再涉及了,想了解就看下面这篇博客吧。
Java并发编程一基本类型、数组类型原子类和累加器初使用加源码分析
AtomicReference
AtomicReference
类会将一个引用类型包装成原子类,现在我们来看一看如何使用吧。
这里我们使用AtomicReference
类来实现一个简易版自旋锁。
代码:
package lock.spinlock;
import java.util.concurrent.atomic.AtomicReference;
public class SpinLock {
private AtomicReference<Thread> sign = new AtomicReference<>();
public void lock() {
Thread current = Thread.currentThread();
while (!sign.compareAndSet(null, current)) {
System.out.println("自旋获取失败,再次尝试");
}
}
public void unlock() {
Thread current = Thread.currentThread();
sign.compareAndSet(current, null);
}
public static void main(String[] args) {
SpinLock spinLock = new SpinLock();
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始尝试获取自旋锁");
spinLock.lock();
System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "释放了自旋锁");
spinLock.unlock();
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
}
}
开头输出:
Thread-1开始尝试获取自旋锁
Thread-0开始尝试获取自旋锁
Thread-1获取到了自旋锁
自旋获取失败,再次尝试
自旋获取失败,再次尝试
自旋获取失败,再次尝试
自旋获取失败,再次尝试
自旋获取失败,再次尝试
结尾输出:
自旋获取失败,再次尝试
自旋获取失败,再次尝试
自旋获取失败,再次尝试
Thread-0释放了自旋锁
自旋获取失败,再次尝试
Thread-1获取到了自旋锁
Thread-1释放了自旋锁
中间输出还有很多的自旋获取失败,再次尝试
。
进入AtomicReference
类源码,可以看到AtomicReference
类将引用类型包装成原子类型的关键-Unsafe
工具类,Unsafe
工具类在之前的那篇博客已经介绍过了,这里就不再赘述。
private static final Unsafe unsafe = Unsafe.getUnsafe();
同样使用反射来获取要操作的属性。
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
使用volatile
关键字修饰value
属性,保证了value
属性的可见性,这和之前讲过的原子类是一样的。
private volatile V value;
我们来看看AtomicReference
类有哪些常用的方法。
/**
* Gets the current value.
*
* @return the current value
*/
public final V get() {
return value;
}
get()
会获取当前的value
。
/**
* Sets to the given value.
*
* @param newValue the new value
*/
public final void set(V newValue) {
value = newValue;
}
set(V newValue)
会进行赋值操作,赋值操作是原子操作,又因为用volatile
关键字修饰了value
属性,保证了value
属性的可见性,这次赋值操作,对其他线程是可见的。
/**
* Atomically sets to the given value and returns the old value.
*
* @param newValue the new value
* @return the previous value
*/
@SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
}
getAndSet(V newValue)
会先获取旧值再赋新值,和之前介绍过的基本类型原子类一样,这些方法都是原子操作,不然就会有线程安全的问题了。
就介绍这些常用的方法吧,其他的方法大家可以自己去看看源码。
AtomicIntegerFieldUpdater
AtomicIntegerFieldUpdater
类,根据类名我们可能就已经知道它的作用了,它是将一个引用类型的int(自动装箱即可)或者Integer
类型的属性升级为与原子类型。
我们来看一看它的用法吧。
代码:
package atomic;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class AtomicIntegerFieldUpdaterDemo implements Runnable{
static Candidate tom;
static Candidate peter;
public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater
.newUpdater(Candidate.class, "score");
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
peter.score++;
scoreUpdater.getAndIncrement(tom);
}
}
public static class Candidate {
volatile int score;
}
public static void main(String[] args) throws InterruptedException {
tom=new Candidate();
peter=new Candidate();
AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("普通变量:"+peter.score);
System.out.println("升级后的结果"+ tom.score);
}
}
输出:
普通变量:18860
升级后的结果20000
很明显,普通变量的++
操作存在线程安全问题,而经过使用AtomicIntegerFieldUpdater
类进行升级的变量就没有线程安全问题了(使用正确的情况下)。
从这段代码可以很容易看出来,这里也使用了反射。
public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater
.newUpdater(Candidate.class, "score");
/**
* Creates and returns an updater for objects with the given field.
* The Class argument is needed to check that reflective types and
* generic types match.
*
* @param tclass the class of the objects holding the field
* @param fieldName the name of the field to be updated
* @param <U> the type of instances of tclass
* @return the updater
* @throws IllegalArgumentException if the field is not a
* volatile integer type
* @throws RuntimeException with a nested reflection-based
* exception if the class does not hold field or is the wrong type,
* or the field is inaccessible to the caller according to Java language
* access control
*/
@CallerSensitive
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
String fieldName) {
return new AtomicIntegerFieldUpdaterImpl<U>
(tclass, fieldName, Reflection.getCallerClass());
}
使用AtomicIntegerFieldUpdater
类进行升级的变量其实就具有了和AtomicInteger
类一样的功能。
部分源码:
public abstract int get(T obj);
public int getAndSet(T obj, int newValue) {
int prev;
do {
prev = get(obj);
} while (!compareAndSet(obj, prev, newValue));
return prev;
}
public int getAndIncrement(T obj) {
int prev, next;
do {
prev = get(obj);
next = prev + 1;
} while (!compareAndSet(obj, prev, next));
return prev;
}
public int getAndDecrement(T obj) {
int prev, next;
do {
prev = get(obj);
next = prev - 1;
} while (!compareAndSet(obj, prev, next));
return prev;
}
public int getAndAdd(T obj, int delta) {
int prev, next;
do {
prev = get(obj);
next = prev + delta;
} while (!compareAndSet(obj, prev, next));
return prev;
}
public int incrementAndGet(T obj) {
int prev, next;
do {
prev = get(obj);
next = prev + 1;
} while (!compareAndSet(obj, prev, next));
return next;
}
public int decrementAndGet(T obj) {
int prev, next;
do {
prev = get(obj);
next = prev - 1;
} while (!compareAndSet(obj, prev, next));
return next;
}
public int addAndGet(T obj, int delta) {
int prev, next;
do {
prev = get(obj);
next = prev + delta;
} while (!compareAndSet(obj, prev, next));
return next;
}
这些方法和AtomicInteger
类中的方法差不多,就不多讲了,可以参考下面这篇博客。
Java并发编程一基本类型、数组类型原子类和累加器初使用加源码分析