volatile实践
1、volatile变量不会被缓存在寄存器或对其它处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
2、volatile只确保变量的可见性并不确保原子性,加锁机制既可确保可见性又可确保原子性。
3、volatile变量对可见性的影响比volatile变量自身的特性更为重要。当线程A首先写入一个volatile变量并且线程B随后读取该变量时,在写入volatile变量之前对A可见的所有变量的值,在B读取了volatile变量后,对B也是可见的。
4、语句重排的问题,编译器和运行时检测到变量为volatile时是不会对该变量上的操作进行重排序(类似synchronized段)。
5、volatile变量的适用场景
5.1、对变量的写入操作不依赖变量的当前值,或者能确保只有单个线程写变量的值。
5.2、volatile变量不会与其它状态变量一起纳入不变性条件中。
5.3、当访问变量时不需要锁。
线程安全的正确性
某个类的行为与其规范完全一致,在良好的规范中通常会定义各种不变性条件来约束对象的状态,以及定义各种后验条件来描述对象操作的结果。
示例代码
这段代码的主要目的是实践一下volatile的不加锁读写特性,而对volatile变量不能保证操作的原子性则没能体现出来。
package org.ybygjy.jcip.chap3;
/**
* 负责构造一个volatile多线程任务处理环境
* <p>1.1、单写多读</p>
* <p>1.2、没有锁</p>
* <p>1.3、volatile确保变量的更新操作对其它线程可见</p>
* <p>1.4、volatile变量不会缓存在寄存器或其它处理器不可见的地方</p>
* <p>1.5、让人沉思的一句话(volatile变量对可见性的影响比volatile变量本身更为重要)</p>
* 注意
* <p>2.1、多线程读的问题,volatile只保证变量的更新操作在无需特殊同步的情况下对其它线程可见</p>
* @author WangYanCheng
* @version 2014-7-17
*/
public class VolatileThreadTest {
public void doWork() {
final VolatileVO volatileVO = new VolatileVO();
VolatileWriteThread writeThread = new VolatileWriteThread(volatileVO);
VolatileReadThread readThread1 = new VolatileReadThread(volatileVO);
VolatileReadThread readThread2 = new VolatileReadThread(volatileVO);
writeThread.start();
readThread1.start();
readThread2.start();
}
/**
* 测试入口
* @param args 参数列表
*/
public static void main(String[] args) {
VolatileThreadTest volatileThreadTest = new VolatileThreadTest();
volatileThreadTest.doWork();
}
/**
* 负责{@link VolatileVO} 写操作
* @author WangYanCheng
* @version 2014-7-17
*/
class VolatileWriteThread extends Thread {
private VolatileVO volatileVo;
public VolatileWriteThread(VolatileVO volatileVO) {
this.volatileVo = volatileVO;
}
@Override
public void run() {
while (true) {
int i = volatileVo.getStep() + 1;
this.volatileVo.setStep(i);
if (i%500 == 0) {
break;
}
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 负责{@link VolatileVO} 读操作
* @author WangYanCheng
* @version 2014-7-17
*/
class VolatileReadThread extends Thread {
private VolatileVO volatileVo;
public VolatileReadThread(VolatileVO volatileVo) {
this.volatileVo = volatileVo;
}
@Override
public void run() {
while (true) {
String tmpValue = getName() + "#" + volatileVo.getStep();
System.out.println(tmpValue);
if (volatileVo.getStep()%500==0) {
break;
}
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 定义数据实体
* @author WangYanCheng
* @version 2014-7-17
*/
class VolatileVO {
/** 使用volatile确保并发环境下值的可见性*/
private volatile int step;
public int getStep() {
return step;
}
public void setStep(int step) {
this.step = step;
}
}
参考资料
1、Java Concurrenty In Practice