1,测试实验,测试有无volatile的区别:
(1)volatile保证线程可见性,
public class T01_HelloVolatile
{
/*volatile*/ boolean runing=true;
void m(){
System.out.println("线程开始");
while (runing)
{
//这里包含了刷新内存的操作
//System.out.println("和咯欧文");
}
System.out.println("end");
}
public static void main(String[] args)
{
T01_HelloVolatile t=new T01_HelloVolatile();
new Thread(t::m,"t1").start();
try
{
TimeUnit.SECONDS.sleep(1);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
t.runing=false;
}
}
结果:
原因:
因为不知道,值已经被另外的一个线程修改了, 依旧使用cpu加载那个runing=true的值,就会一直卡在循环中,添加了volatile之后,那么当主线程修改之后,CPU1 的线程会重新读取runing的值,从而结束循环。
2,测试实验,CPU会出现指令重排
(1)什么是指令重排?
在虚拟机层面为了尽可能减少内存操作速度远慢于CPU运行速度所带来的CPU空置的影响,虚拟机会按照自己的一些规则将程序编写顺序打乱——即写在后面的代码在时间顺序上可能会先执行,而写在前面的代码会后执行——以尽可能充分地利用CPU。
(2)代码实际测试:
这是一道很经典的笔试题,我真的遇到:
public class T04_Disorder
{
static int x,y,a,b;
public static void main(String[] args) throws InterruptedException
{
int i=0;
for (;;)
{
i++;
x=0;y=0;
a=0;b=0;
Thread one=new Thread(new Runnable()
{
@Override
public void run()
{
a=1;
x=b;
}
});
Thread two=new Thread(new Runnable()
{
@Override
public void run()
{
b=1;
y=a;
}
});
one.start();two.start();
one.join();two.join();
String result="第"+i+"次 ( "+x+" , "+y+")";
if (x==0&&y==0)
{
System.out.println(result);
break;
}
}
}
}
(3)解释说明(假设没有指令重排):
假设没有指令重排则x和y的值可能是:
如果,线程one执行:x=0,y=1
如果,线程two先执行:x=1.,y=0
也就说不可能出现:x=0,y=0情况。
也就是说,如果不存在指令重排,则不会执行下列代码:
但是
(4)最终输出结果:
(5)结论:存在指令重排。
(6)解决指令重排序:
1:volatile
2,ACC_VOLATILE
3,JVM内存屏障。
—屏障两端的指令不能重排!保障有序
JVM虚拟机06:JSR内存屏障
4,hotspot实现