volatile关键字

/ 多线程 / 没有评论 / 316浏览

volatile关键字的作用就是使变量在多个线程间可见。这到底是什么意思呢?我们先看下面的事例然后在详细说明。

/**
* 用户登录
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-15 10:35
* @since 1.0.0
*/
public class Userinfo extends Thread {

private boolean isRuning = true;

public void setRuning(boolean runing) {
isRuning = runing;
}

@Override
public void run() {
System.out.println("循环开始了");
while (isRuning) {
}
System.out.println("循环结束了");
}
}
/**
* 测试类
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-15 10:49
* @since 1.0.0
*/
public class RequestRun {
public static void main(String[] args) throws InterruptedException {
Userinfo userinfo = new Userinfo();
userinfo.start();
Thread.sleep(1000);
userinfo.setRuning(false);
}
}
循环开始了

我们看线程进入了循环停止不了了,虽然我们设置isRuning属性等于false但是循环还是没有停止,这到底是什么原因呢?要想知道这个问题的产生原因我们就要先了解线程的内存结构。这里我们只是简单的了解一下,在后面的文章中我们在重点介绍Java中线程的内存模型。实际上在Java中多线程都有一个自己的内存空间,每个线程的内存空间与其它线程内存空间是不同步的,也就是说不同的线程与线程之间是无法直接交互的。它们是通过主内存来交互的。当多线程执行时,它会先把主内存中的属性拷贝到自己的线程内存中然后在去执行具体的逻辑操作,当处理完毕后在将处理结果同步到主内存中。如果两个线程是异步执行的,那它们都会把主内存中的数据拷贝到自己的内存空间中处理,当处理完毕后都会将自己的处理数据同步到主内存中,这也是开发多线程程序有线程安全问题的根本原因。就是在多个线程都将自己线程内存中的数据同步到主内存中产生的问题。上述代码出现循环不结束的原因是因为当线程启动后会将isRuning属性拷贝到自己的线程内存中,然后执行循环,这时我们虽然设置了isRuning属性为false,但是这设置的是主内存的属性值,线程中的isRuning属性还是true,线程不会在去主内存中取值,所以程序还是会一直执行循环的。那怎么样才能解决这个问题呢 ,可能有人会想说用synchronized同步方法,但按照我们上述所分析的,这不是多个线程同时访问实例变量产生的问题,而是线程内存与主内存不同步的问题,显然用synchronized是解决不了上述问题的。那么怎么办呢?放心在Java中还提供了一个关键字来解决类似上述问题所产生的线程安全,它就是volatile关键字。这也是我在文章开头所说的。volatile关键字的作用就是使变量在多个线程间可见。看它的说明感觉挺让人费解的。那我们简单点说明就是用volatile关键字修饰的变量只能保存在主内存中,或者说线程在使用volatile数据时只能去主内存中是取值。也可以理解为每个线程在拷贝主内存数据到自己的线程内存时,volatile关键字修饰的变量是拷贝不了的。这也就保证了无论有多少个线程,如果它们需要使用volatile关键字修饰的变量,那只能去主内存中是取值。这恰恰是我们想要的,所以上述的代码我们只需添加一个volatile关键字就能解决死循环的问题了。

/**
* 用户登录
*
* @author Sama
* @author admin@jilinwula.com
* @date 2017-03-15 10:35
* @since 1.0.0
*/
public class Userinfo extends Thread {

private volatile boolean isRuning = true;

public void setRuning(boolean runing) {
isRuning = runing;
}

@Override
public synchronized void run() {
System.out.println("循环开始了");
while (isRuning) {
}
System.out.println("循环结束了");
}
}
循环开始了
循环结束了

我们看循环结束了,原因就是像我们刚刚所说的那样。在实际的开发中volatile关键字在多线程中我们经常使用。

121212.jpg

多线程内存模型