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.解决同步死循环ide
将一中的代码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); } }
运行结果:this
但当上面的实例代码运行在 -server服务器模式的64位的JVM上时,会出现死循环,解决的办法是使用volatile关键字.线程
volatile关键字的做用是强制从公共堆栈中取得变量的值,而不是从线程使用数据栈中取得变量的值server
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自己并不处理数据的原子性,而是强制对数据的读写及时影响到主内存.