java volatile关键字

volatile关键字的主要作用是使变量在多个线程间可见。

关键字volatile的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。

1、关键字volatile与死循环:

package com.test;

public class PringString {
    private boolean isContinuePrint = true;

    public boolean isContinuePrint() {
        return isContinuePrint;
    }

    public void setContinuePrint(boolean isContinuePrint) {
        this.isContinuePrint = isContinuePrint;
    }
    
    public void printStringMethod() {
        try {
            while (isContinuePrint == true) {
                System.out.println("run printStringMethod");
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
package com.test;

public class Run {
    
    public static void main(String[] args) {
        
        PringString print = new PringString();
        print.printStringMethod();
        System.out.println("我要停止它");
        print.setContinuePrint(false);
    }
}
运行结果:
run printStringMethod
run printStringMethod
run printStringMethod
run printStringMethod

程序开始运行后,根本停不下来。因为main线程一直在处理while循环,导致程序不能继续执行后边的代码。解决的办法当然是多线程技术。

修改PringString.java:

package com.test;

public class PringString extends Thread {
    volatile private boolean isContinuePrint = true;

    public boolean isContinuePrint() {
        return isContinuePrint;
    }

    public void setContinuePrint(boolean isContinuePrint) {
        this.isContinuePrint = isContinuePrint;
    }
    
    @Override
    public void run() {
        try {
            System.out.println("进入run了");
            while (isContinuePrint == true) {
                System.out.println("run printStringMethod");
                Thread.sleep(1000);
            }
            System.out.println("线程被停止了");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}
package com.test;

public class Run {
    
    public static void main(String[] args) {
        
        try {
            PringString print = new PringString();
            print.start();
            Thread.sleep(1000);
            print.setContinuePrint(false);
            System.out.println("已经赋值为false");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
运行结果:
进入run了
run printStringMethod
run printStringMethod
已经赋值为false
线程被停止了

总结:

使用volatile关键字增加了实例变量在多个线程之间的可见性。但volatile关键字最致命的缺点是不支持原子性。

下面是关键字synchronized和volatile进行一下比较:

  1. 关键字volatile是线程同步的轻量级实现,所以性能要比synchronized要好。并且volatile只能修饰于变量,而synchronized可以修饰方法,以及代码块。
  2. 多线程访问volatile不会发生阻塞,而synchronized会发生阻塞。
  3. volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性。因为它会将私有内存和公有内存中的数据做同步。
  4. volatile解决的是多个线程之间的可见性,而synchronized解决的是多线程之间的同步性.

关键字volatile主要使用场合是多个线程中可以感知实例变量被更改了,并且可以获得最新的使用值,此关键字提示线程每次从共享内存中读取变量,而不是从私有内存中读取,这样就保证了同步数据的可见性,但需要注意的是:如果修改实例变量中的数据,比如i++,就是i=i+1则这样的操作其实并不是一个原子操作,也就是非线程安全的。