8.1、volatile 关键字的概念
自 Java1.5 版本起, volatile 关鍵字所扮演的角色越来越重要,该关鍵字也成为并 发包的基础,所有的原子数据类型都以此作为修饰,相比 synchronized 关键字,volatile 被称为“轻量级锁”,能实现部分 synchronized 关键字的语义。
volatile 概念: volatile 关键字的主要作用是使变量在多个线程间可见。下面我们 通过一个案例来了解一下 volatile:
代码1:未加volatile关键字,一个线程读取变量为true死循环,main线程设置变量为false
package com.bjsxt.chapter08;
import java.util.concurrent.TimeUnit;
public class VolatileDemo extends Thread {
private boolean isRunning = true;// 注意 未加 volatile 修饰的普通变量
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " start run...");
while(isRunning){
//...
}
System.out.println(Thread.currentThread().getName() + " end run...");
}
public static void main(String[] args) throws InterruptedException {
VolatileDemo vd = new VolatileDemo();
vd.start();
TimeUnit.SECONDS.sleep(1);
vd.isRunning = false;
System.out.println("main thread set isRunning false");
}
}
运行结果:代码处于死循环
分析:main线程获取的是自己工作区的isRunning,赋值后写回到所有线程共享变量中。但是,线程Thread-0使用的是自己工作区的isRunning:true。没有装入步骤。
装入:从共享内存拿数据放进Thread-0线程工作内存
写回:将Thread-0线程工作内存中数据写回共享内存
代码2:循环体中加入System.out.print…
package com.bjsxt.chapter08;
import java.util.concurrent.TimeUnit;
public class VolatileDemo001 extends Thread {
private boolean isRunning = true;// 注意 未加 volatile 修饰的普通变量
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " start run...");
while(isRunning){
//System.out.print("");
//System.out.printf("");
System.out.println("");// 以上输出会导致当前线程重新装入
}
System.out.println(Thread.currentThread().getName() + " end run...");
}
public static void main(String[] args) throws InterruptedException {
VolatileDemo001 vd = new VolatileDemo001();
vd.start();
TimeUnit.SECONDS.sleep(1);
vd.isRunning = false;
System.out.println("main thread set isRunning false");
}
}
运行结果:Thread-0的工作内存数据是false。程序不再死循环。
分析:System.out.print…方法会使得 从共享内存拿数据放进Thread-0线程工作内存,导致程序不在死循环。
代码3:使用 synchronized 解决死循环问题
package com.bjsxt.chapter08;
import java.util.concurrent.TimeUnit;
public class VolatileDemo03 extends Thread {
private boolean isRunning = true;// 注意 未加 volatile 修饰的普通变量
public synchronized void setRunning(boolean x){
this.isRunning = x;
}
public synchronized boolean getRunning(){
return this.isRunning;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " start run...");
while(getRunning()){
//...
}
System.out.println(Thread.currentThread().getName() + " end run...");
}
p