标签:并发 多线程 lazyset unsafe putorderedint
看过java.util.concurrent.atomic包里面各个AtomicXXX类实现的同学应该见过lazySet方法,比如AtomicBoolean类的lazySet方法
public final void lazySet(boolean newValue) {
int v = newValue ? 1 : 0;
unsafe.putOrderedInt(this, valueOffset, v);
}它的意思是putOrderedXXX方法是putXXXVolatile方法的延迟实现,不保证值的改变被其他线程立即看到
<span><span><span style="font-family:Calibri;font-size:12px;"> /*** * Sets the value of the integer field at the specified offset in the * supplied object to the given value. This is an ordered or lazy * version of <code>putIntVolatile(Object,long,int)</code>, which * doesn't guarantee the immediate visibility of the change to other * threads. It is only really useful where the integer field is * <code>volatile</code>, and is thus expected to change unexpectedly. * 设置obj对象中offset偏移地址对应的整型field的值为指定值。这是一个有序或者 * 有延迟的<code>putIntVolatile</cdoe>方法,并且不保证值的改变被其他线程立 * 即看到。只有在field被<code>volatile</code>修饰并且期望被意外修改的时候 * 使用才有用。 * * @param obj the object containing the field to modify. * 包含需要修改field的对象 * @param offset the offset of the integer field within <code>obj</code>. * <code>obj</code>中整型field的偏移量 * @param value the new value of the field. * field将被设置的新值 * @see #putIntVolatile(Object,long,int) */</span></span></span> <span><span><span style="font-family:Calibri;font-size:12px;"> public native void putOrderedInt(Object obj, long offset, int value);</span></span></span>
理解volatile底层实现的同学知道,volatile的实现最终是加了内存屏障,
1. 保证写volatile变量会强制把CPU写缓存区的数据刷新到内存
2. 读volatile变量时,使缓存失效,强制从内存中读取最新的值
3. 由于内存屏障的存在,volatile变量还能阻止重排序
所以volatile变量的修改可以立刻让所有的线程可见,保证了可见性。而不加volatile变量的字段,JMM不保证普通变量的修改立刻被所有的线程可见。所以lazySet说白了就是以普通变量的方式来写变量。
// 对flagA的修改对所有线程立刻可见 volatile boolean flagA; // 对flagB的修改不能立刻被其他线程可见 boolean flagB;
在这篇 聊聊高并发(十六)实现一个简单的可重入锁 中我们实现了一个可重入锁,里面共享变量用了volatile变量,来保证对共享变量的修改对其他线程可见。
但是事实上,这里完全可以不用volatile变量来修饰这些共享状态,
1. 因为访问共享状态之前先要获得锁, Lock.lock()方法能够获得锁,而获得锁的操作和volatile变量的读操作一样,会强制使CPU缓存失效,强制从内存读取变量。
2. Lock.unlock()方法释放锁时,和写volatile变量一样,会强制刷新CPU写缓冲区,把缓存数据写到主内存
底层也是通过加内存屏障实现的。
package com.zc.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 简单的可重入锁实现,使用一个计数器记录当前线程重入锁的次数,获得锁时计数器加1,释放锁时计数器减1,当计数器等于0时表示释放了锁
* **/
public class SimpleReentrantLock implements Lock{
// 指向已经获得锁的线程
private volatile Thread exclusiveOwnerThread;
// 记录获取了同一个锁的次数
private volatile int holdCount;
private final java.util.concurrent.locks.Lock lock;
// 是否是自己获得锁的条件
private final Condition isCountZero;
public SimpleReentrantLock(){
lock = new ReentrantLock();
isCountZero = lock.newCondition();
holdCount = 0;
}
@Override
public void lock() {
lock.lock();
try{
// 当前线程的引用
Thread currentThread = Thread.currentThread();
// 如果获得锁的线程是自己,那么计数器加1,直接返回
if(exclusiveOwnerThread == currentThread){
holdCount ++;
return;
}
while(holdCount != 0){
try {
isCountZero.await();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted");
}
}
// 将exclusiveOwnerThread设置为自己
exclusiveOwnerThread = currentThread;
holdCount ++;
}finally{
lock.unlock();
}
} 下面的例子来自StackOverflow上的一个提问,说的也是类似的意思,就是优化不必要的volatile操作。被墙的同学看不到,可以看截图。
聊聊高并发(十八)理解AtomicXXX.lazySet方法
标签:并发 多线程 lazyset unsafe putorderedint
原文地址:http://blog.csdn.net/iter_zc/article/details/40744485