说明:参考《Java多线程核心技术》
13、volatile关键字
volatile关键字的作用:使变量在多个线程之间可见。
如果不是在在多继承的情况下,使用继承Thread和实现Runnable接口没有多大的区别。但是一旦出现多继承的情况,则用实现Runnable的方式处理多线程是个很有必要的。
public class PrintString implements Runnable{
private boolean isContinue = true;
public boolean isContinue() {
return isContinue;
}
public void setContinue(boolean isContinue) {
isContinue = isContinue;
}
public void printStringService() {
try {
while (isContinue == true) {
System.out.println("ThreadName " + Thread.currentThread().getName());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
printStringService();
}
}
public class PrintStringTest {
public static void main(String[] args) {
PrintString printString = new PrintString();
new Thread(printString).start();
System.out.println("stop it... stopThreadName " + Thread.currentThread().getName());
printString.setContinue(false);
}
}
/** dead loop
stop it... stopThreadName main
ThreadName Thread-0
ThreadName Thread-0
ThreadName Thread-0
*/
关键字volatile的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中入得变量的值。
使用关键字volatile增加了实例变量在多个线程之间的可见性。
14、volatile和synchronized比较
关键字volatile和synchronized的比较:
1、关键字volatile是线程同步的轻量级的实现,所以volatile性能肯定比synchronized好,并且volatile只能修饰变量,而synchronized可以修饰方法和代码块、但是随着JDK版本的提升,synchronized关键字在效率上有了很大的提升。
2、多线程访问volatile不会发生阻塞,但是synchronized会发生阻塞。
3、volatile能保证共享变量之间的可见性,但是不能保证原子性;而synchronized能保证原子性,也可以间接保证共享变量的可见性格,因为它会将私有内存共有内存中的数据做同步。
4、volatile关键字解决的是变量在多个线程之间的可见性,而synchronized关键字解决的是多个线程之间访问资源的同步性。
15、volatile的非原子特性
关键字volatile虽然增减了实例变量在多个线程之间的可见性,但它却不具备同步性,那么就不具备原子性。
public class UnAtomicity extends Thread{
volatile public static int count;
private static void addCount(){
for (int i = 0; i < 100; i++) {
count++;
}
System.out.println("count = " + count);
}
@Override
public void run(){
addCount();
}
}
public class UnAtomicityTest {
public static void main(String[] args) {
UnAtomicity[] unAtomicities = new UnAtomicity[100];
for (int i = 0; i < 100 ; i++) {
unAtomicities[i] = new UnAtomicity();
unAtomicities[i].start();
}
}
}
/**
count = 9686
count = 9886
count = 9886
count = 9786
count = 9786
count = 9786
count = 9786
*/
关键字volatile提示线程每次从共享内存中读取变量,而不是从内存中读取,这样就保证了同步数据的可见性。
表达式i++:并不是一个操作,而是三个,因此才会造成上述的现象:
1、从内存中读取i的值
2、计算i的值
3、将i的值写入内存中。
如果将 volatile public static int count;改为 synchronized public static int count; 就不会发生上述的线程。注意必须加static关键字,这样才能锁住Class类了。
总结:
关键字volatile对于修饰的变量,JVM虚拟机只是保证从主存中加载到线程工作内存的值是最新的。其解决的是变量在读操作时的可见性问题,但无法保证原子性,对于多个线程访问同一变量还是需要加锁同步的。
关键字synchronized可以保证同一时刻,只有一个线程可以执行某一方法或者某一个代码块,其包含了两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还可以保证进入同步方法或者同步代码块的每个线程,都可到由同一个锁保护之前的所有修改结果。