多线程(三)~多线程中数据的可见性-volatile关键字
我们先来看一段代码:
①.线程类,用全局布尔值控制线程是否结束,每隔1s打印一次当前线程的信息
package com.multiThread.thread;
publicclassPrintStringimplementsRunnable{
privateboolean isContinuePrint =true;
@Override
publicvoid run(){
while(isContinuePrint){
try{
System.out.println("current threadId is "+Thread.currentThread().getId()+",threadName is"+Thread.currentThread().getName()+",threadPriority "+Thread.currentThread().getPriority());
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("Thread is stop!");
}
publicboolean isContinuePrint(){
return isContinuePrint;
}
publicvoid setContinuePrint(boolean isContinuePrint){
this.isContinuePrint = isContinuePrint;
}
}
②.测试类
package com.multiThread.test.common;
import com.multiThread.thread.PrintString;
publicclassVolatileTest{
publicstaticvoid main(String[] args){
PrintString printString =newPrintString();
Thread t =newThread(printString);
t.start();
try{
Thread.sleep(2000);
printString.setContinuePrint(false);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
打印结果:
current threadId is 8,threadName isThread-0,threadPriority 5
current threadId is 8,threadName isThread-0,threadPriority 5
Thread is stop!
以上这段程序在我本地的eclipse上运行完全没有问题,但是一段以服务器端的参数来运行则会出现问题。
我们修改一下eclipse的运行方式,带上参数-server来运行这段代码,擦,运行结果还是这样,又没成功,我命名是win7+jdk64位啊。
先不管了,按照书上说的,这块停不下来。那为什么停不下来呢?因为服务器为了兼顾性能直接从当前线程的工作内存中获取的值,没有从主内存中取。而main函数里的操作是把主内存的数据给更新了,听起来类似于程序的读缓存没查库的操作。
解决的方式就是为变量此变量加上volatile关键字来修饰。volatile关键字修饰的变量会强制从主内存中读取数据,保证数据的可见性。
此关键字的应用场景为:多线程中可以感知实例变量被更改了。并且可以获得最新的值使用,也就是多线程读取共享变量时可以获得最新的值使用
privatevolatileboolean isContinuePrint =true;
附带volatile关键字的工作图:
当然,此处也可以采用synchronize的方式来处理,不过synchronize和volatile关键字的作用是不同的。
这里要注重强调一下二者的区别和作用:
volatile:强制从主内存读取数据,保证数据的可见性。volatile的操作不是原子性的。
synchronize:同步操作,保证一次监视对象一次只有一个线程去处理。synchronize本身也可以保证数据的可见性,同时更重要的是用来保证数据的同步性。
多线程这块的处理都是围绕着数据的同步性、可见性和原子性来操作的,记住这个原则就OK。
下一章我们来看一下和原子性有关的操作。
用一张图来描述变量在内存中的工作流程: