在JAVA中,当程序运行的时候,除了main memory(主寄存器),JVM也都会为每一个线程分配一个独立的缓存,用于极高效率。每个线程都会在自己的memory中保存要访问变量的副本。如图所示:
这样当线程值改变时候,再去更新主存中的值,或者主存中的值改变时,再去更新线程中的值,以达到值一致的情况。但是会出现线程中副本值和主存中的值或者另外的线程中副本值不一样的情况的瞬间。
如下代码所示:
public class Test
{
public static void main(String[] args) throws InterruptedException
{
ThreadDemo threadDemo = new ThreadDemo();//创建Runnable接口对象
Thread thread = new Thread(threadDemo);//创建线程对象
thread.start();//开启线程
while(true)
{
//Thread.sleep(10);
if(threadDemo.getFlag()) //判断标志位
{
System.err.println(Thread.currentThread().getName()+" : "+threadDemo.getFlag());
break;
}
}
}
}
class ThreadDemo implements Runnable
{
private boolean flag = false;
public boolean getFlag()
{
return flag;
}
public void setFlag(boolean flag)
{
this.flag = flag;
}
@Override
public void run()
{
try
{
Thread.sleep(300);
flag = true;//修改标志位的值
System.out.println(Thread.currentThread().getName()+" : "+flag);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
输出结果如下:
Thread-0 : true
从结果可以看出,thread-0修改了标志位flag = true,但是在主线程中获取标志位盛然是false。
可以尝试在主线程的while循环里面让main线程停留一会儿便会将main线程缓存中的值进行刷新。上述问题称为内存可见性问题,即当多个线程操作共享数据时,彼此独立(不可见)引起的。
解决内存可见性问题问题:
1.通过同步锁可以解决。
2.通过volatile关键字解决。声明一个变量为volatile,则意味着这个变量不会被存储在线程缓存中,保证内存中的数据可见性。相较于synchronized是一种较为轻量级的同步策略。
同时volatile不具备"互斥性"、不能保证变量的"原子性"。
修改代码如下:
{
public static void main(String[] args) throws InterruptedException
{
ThreadDemo threadDemo = new ThreadDemo();//创建Runnable接口对象
Thread thread = new Thread(threadDemo);//创建线程对象
thread.start();//开启线程
while(true)
{
//Thread.sleep(10);
if(threadDemo.getFlag()) //判断标志位
{
System.err.println(Thread.currentThread().getName()+" : "+threadDemo.getFlag());
break;
}
}
}
}
class ThreadDemo implements Runnable
{
private volatile boolean flag = false;
public boolean getFlag()
{
return flag;
}
public void setFlag(boolean flag)
{
this.flag = flag;
}
@Override
public void run()
{
try
{
Thread.sleep(300);
flag = true;//修改标志位的值
System.out.println(Thread.currentThread().getName()+" : "+flag);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
运行结果如下:
Thread-0 : true
main : true