volatile的作用是使变量在多个线程间可见
1.死循环
public class PrintInfo implements Runnable {
private boolean statu = true;
public boolean isStatu() {
return statu;
}
public void setStatu(boolean statu) {
this.statu = statu;
}
public void printInfo() {
try {
while(statu == true){
System.out.println("The Thread Name Is " + Thread.currentThread().getName());
Thread.sleep(1000);
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
printInfo();
}
}
public class Run {
public static void main(String[] args){
PrintInfo printInfo = new PrintInfo();
printInfo.printInfo();
System.out.println("Try To Stop The Thread");
printInfo.setStatu(false);
}
}
运行结果:

2.解决同步死循环
将一中的代码Run类修改为
public class Run {
public static void main(String[] args) throws InterruptedException {
PrintInfo printInfo = new PrintInfo();
Thread thread = new Thread(printInfo);
thread.start();
Thread.sleep(1000);
System.out.println("Try To Stop The Thread");
printInfo.setStatu(false);
}
}
运行结果:

但当上面的实例代码运行在 -server服务器模式的64位的JVM上时,会出现死循环,解决的办法是使用volatile关键字.
volatile关键字的作用是强制从公共堆栈中取得变量的值,而不是从线程使用数据栈中取得变量的值
3.解决异步死循环
将1中的代码PrintInfo修改为
public class PrintInfo implements Runnable {
volatile private boolean statu = true;
public boolean isStatu() {
return statu;
}
public void setStatu(boolean statu) {
this.statu = statu;
}
public void printInfo() {
try {
while(statu == true){
System.out.println("The Thread Name Is " + Thread.currentThread().getName());
Thread.sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
printInfo();
}
}
运行结果:

4.关键字synchronized与volatile的区别
使用volatile关键字增加了实例变量在多个线程之间的可见性,但是volatile关键字的缺点是不支持原子性.
1).关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰于变量,二synchronized可以修饰方法,以及代码块.随着JDK新版本的发布,synchronized关键字的执行效率得到很大提升,在开发中使用synchronized关键字的比例还是比较大.
2).多线程访问volatile不会发生阻塞,二synchronized回出现阻塞
3).volatile能保证数据的可见性.但不能保证原子性,而synchronized可以保证原子性,也可以间接保证可见性,以内他会将使用内存和公共内存中的数据做同步.
4).关键字volatile解决的是变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性,
线程安全包含原子性和可见性两个方面,JAVA的同步机制都是围绕这两个方面来确保线程安全的.
5.volatile的非原子特性
public class VolatileThread extends Thread{
volatile public static int count ;
private static void sumCount(){
for(int i = 0 ; i < 10 ; i ++){
count ++;
}
System.out.println("count = " + count);
}
@Override
public void run() {
sumCount();
}
}
public class Run {
public static void main(String[] args){
VolatileThread[] volatileThreads = new VolatileThread[100];
for(int i = 0 ; i < 10 ; i ++){
volatileThreads[i] = new VolatileThread();
}
for(int i = 0 ; i < 10 ; i ++){
volatileThreads[i].start();
}
}
}
运行结果:

更改VolatileThread类代码为:
public class VolatileThread extends Thread{
volatile public static int count ;
synchronized private static void sumCount(){
for(int i = 0 ; i < 10 ; i ++){
count ++;
}
System.out.println("count = " + count);
}
@Override
public void run() {
sumCount();
}
}
运行结果:

关键字volatile主要使用的场合是在多个线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量时可以获取最新值使用.
关键字volatile提示线程每次从共享内存中读取变量,而不是从私有内存中读取,这样就保证了同步数据的可见性,但需要注意的是:如果修改实例变量中的数据,比如i++,这样的操作其实并不是一个院子操作,也就是非线程安全的.
表达式i++的操作不走分解如下:
1).从内存中获取i的值,
2).计算i的值,
3).将计算后的值存储到内存中.
如果在第二步时,另一个线程也修改了i的值,那么这个时候就会出现脏数据,解决的办法就是使用synchronized关键字,所以volatile本身并不处理数据的原子性,而是强制对数据的读写及时影响到主内存.
来源:oschina
链接:https://my.oschina.net/u/2310587/blog/746362