闲聊
这是一个测试volatile的例子。
首先我们td不添加volatile,以下的逻辑,创建一个线程让它去修改该flag,但不是让它立刻去修改,,而是先让子线程休息一段时间,好让主线程进入狂读flag的状态,这样做是为了防止低运行强度下 cpu主动刷新了缓存。之后我们进行修改。
public class VolatileTest {
static ThreadDemo td = new ThreadDemo();
public static void main(String[] args) {
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("================");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("falg=" + flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
得到结果如下
falg=true
我们发现子线程的值已经进行修改,但这并不能证明内存中的值已被写入。
为证明内存里的已经被写入,只是主线程没读取罢了,做了如下测试
public class VolatileTest {
static ThreadDemo td = new ThreadDemo();
public static void main(String[] args) {
new Thread(td).start();
new Thread(new ThreadDemo2()).start();
while (true) {
if (td.isFlag()) {
System.out.println("================");
break;
}
}
}
static class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("falg=" + flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
static class ThreadDemo2 implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("ThreadDemo2" + VolatileTest.td.flag);
}
}
}
得到结果
falg=true
ThreadDemo2true
因为Demo2线程是等了一秒后才从内存开始读,由此证明只是主线层没有刷新缓存。
接下来我们加上volatile。
public class VolatileTest {
static volatile ThreadDemo td = new ThreadDemo();
public static void main(String[] args) {
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("================");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("falg=" + flag);
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
得到结果如下。
================
falg=true
表示该值再被重新读取时,会被及时刷新。
结论
通过这几个demo得出结论正常的写入操作会被及时写入内存,但并不会通知其他的线程,读取操作就是正常的copy内存中的数据,并放到缓存中。加上volatile的写入,可以在其他线程发生读取时,及时的刷新缓存。当然volatile也有禁止重排序的功能,在本篇不进行测试。