多线程之volatile关键字

Posted 街头小瘪三

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程之volatile关键字相关的知识,希望对你有一定的参考价值。

开始全文之前,先铺垫一下jvm基础知识以及线程栈:

JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。

 
 
 
接下来说说volatile:

用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最的值。volatile很容易被误用,用来进行原子性操作。如果要深入了解volatile关键字的作用,就必须先来了解一下JVM在运行时候的内存分配过程。在 java 垃圾回收整理一文中,描述了jvm运行时刻内存的分配。其中有一个内存区域是jvm虚拟机栈,每一个线程运行时都有一个线程栈,线程栈保存了线程运行时候变量值信息。当线程访问某一个对象时候值的时候,首先通过对象的引用找到对应在堆内存的变量的值,然后把堆内存变量的具体值load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆内存变量值有任何关系,而是直接修改副本变量的值,在修改完之后的某一个时刻(线程退出之前),自动把线程变量副本的值回写到对象在堆中变量。这样在堆中的对象的值就产生变化了。下面一幅图描述这写交互!

 
 
有了以上知识做铺垫,接下来直接上代码:
package thread;

public class VolatiDemo1
{
	private static volatile boolean flag = true;
	private static final ThreadLocal <Integer> length = new ThreadLocal <Integer>(){
		@Override
		protected Integer initialValue()
		{
			return 60;
		}
	};
	
	public static void main(String[] args)
	{
		//模拟兔子
		new Thread(new Runnable()
		{
			int rabbitLength = 0;
			@Override
			public void run()
			{
				while(flag){
					try
					{
						Thread.sleep(1000);
						rabbitLength = rabbitLength + 3;
						System.out.println("兔子跑了 rabbitLength " + rabbitLength + " 米,还剩下:"+
								(length.get() - rabbitLength) +" 米--------------------");
						
						if(rabbitLength == length.get())
						{
							System.out.println("兔子获得第一名");
							flag = false;
						}
					} catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}).start();
		
		//模拟乌龟
		new Thread(new Runnable()
		{
			int tortoiseLength = 0;
			@Override
			public void run()
			{
				while(flag){
					try
					{
						Thread.sleep(1000);
						tortoiseLength = tortoiseLength + 1;
						System.out.println("乌龟 跑了 tortoiseLength " + tortoiseLength + " 米,还剩下 "
								+ (length.get() -tortoiseLength) +"米");
						
						if(tortoiseLength == length.get())
						{
							System.out.println("乌龟获得第一名");
							flag = false;
						}
					} catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}).start();
		
		try
		{
			Thread.sleep(8000);
			flag = false;
		} catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}	
}
	

  

 

以上是关于多线程之volatile关键字的主要内容,如果未能解决你的问题,请参考以下文章

java多线程之volatile讲解

多线程之volatile关键字

Java——多线程高并发系列之volatile关键字

Java——多线程高并发系列之volatile关键字

Java多线程之synchronized和volatile的比较

JAVA多线程之volatile 与 synchronized 的比较