主要作用,使变量在多个线程间可见。
1.volatile与死循环
当一个类继承了Thread或者实现Runnable接口,该类中的属性在类的初始化时是存放在线程的公共堆栈中和线程的私有堆栈中,当两个地方的值不一样时,则会产生线程的死循环。使用volatile关键字,强制从公共堆栈中取值,增加了实例变量在多个线程间的可见性,但是,volatile是不支持原子性操作。
2.volatile的非原子特性
i++操作步骤
1)从内存中取出i
2)计算i的值
3)将i的值写道内存中
volatile提示线程每次从主内存中读取变量,在第二步操作时,如果有别的线程操作i的值,就会出现脏读,所以不能保证处理数据的原子性,而是强制对数据的读写及时影响到主内存的。
原因如下:
1)read和load阶段:从主内存复制变量到当前线程私有内存
2)use和assign阶段:执行代码,改变共享变量的值
3)store和write阶段:当前线程私有内存中的变量刷新主内存中对应的变量值
图形如下:
3.volatile与synchronized比较
1)关键字volatile是线程同步的轻量级的实现,所以它的性能优越于synchronized,并且volatile只能修饰变量,而synchronized可以修饰方法、代码块,随着jdk版本的提升,synchronized的效率也会得到提高,代码中的比率相对也叫大。
2)多线程访问volatile不会发生线程阻塞,而synchronized会发生阻塞。
3)volatile能够保证数据的可见性,却不能保证数据的原子性操作,而synchronized可以保证数据的原子性,也可以间接的保证数据的可见性,因为,它会将私有内存和公有内存中的数据做同步。
4)注:volatile解决的是变量在线程间的可见性,而synchronized解决的是多线程之间访问资源的同步性。java线程安全,包含原子性和可见性两个方面,java的同步机制都是围绕着这两个方面来确保线程安全性的。