volatile 关键的作用是使变量在多个线程之间可见,可以强制线程从公共内存中读取变量的值,而不是从工作内存中取,解决了线程的可见性。但其不具有原子特性。
有关volatile的可见性代码示例:
package com.company.volatilekw;
public class Test02 {
public static void main(String[] args) {
PrintString printString=new PrintString();
//开启子线程,让子线程执行printString的printStringMethod()方法
new Thread(new Runnable() {
@Override
public void run() {
//打印字符串
printString.printStringMethod();
}
}).start();
//让main线程睡眠1000毫秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("在main线程中修改打印标志");
printString.setContinuePrint(false);
//查看线程是否会终止打印
//程序运行后,会出现死循环情况,原因是main线程修改了PrintString对象的修改标志后,子线程读不到(前面java工作内存篇提到过,每个子线程
//都有自己的工作内存)
//解决方法是:使用volatile关键字修饰printString对象的打印标志,volatile的作用可以强制线程从公共内存中读取变量的值,
//而不是从工作内存中取,解决了线程的可见性
}
//定义打印字符串类
static class PrintString{
//private boolean continuePrint=true;
//使用volatile修饰
private volatile boolean continuePrint=true;
public PrintString setContinuePrint(boolean continuePrint){
this.continuePrint=continuePrint;
return this;
}
public void printStringMethod(){
while (continuePrint){
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
volatile非原子特性代码示例:
package com.company.volatilekw;
public class Test03 {
public static void main(String[] args) {
//在main线程中创建10个子线程
for (int i = 0; i < 10; i++) {
new MyThread().start();
}
//子线程最后执行的结果末尾数不都是0,说明count++不是原子操作
}
static class MyThread extends Thread{
public volatile static int count;
//可以使用synchronized保证count 的原子性
//public synchronized static void addCount(){
public static void addCount(){
for (int i = 0; i < 1000; i++) {
count++;
}
System.out.println(Thread.currentThread().getName()+"count="+count);
}
@Override
public void run() {
addCount();
}
}
}