参考:https://blog.csdn.net/weixin_73077810/article/details/132804522
内存屏障主要用于解决线程的可见性、有序性问题
代码案例:
ReentrantLock保证可见性的原理
在 lock.lock() 和 lock.unlock() 时,都会操作 AbstractQueuedSynchronizer类 中的一个变量 state,这个变量是 volatile 修饰的,volatile变量的语句对应的汇编码指令中会多加一行lock addl $0x0, (%esp),这一行的作用是:
(1)将工作内存修改了的缓存(不仅仅是该变量的缓存)都强制刷新回主内存
(2)把其他CPU对应缓存行标记为invalid状态,那么在读取这一部分缓存时,必须回主内存读取。这样也就保证了线程间的可见性
具体来说,当一个线程获取ReentrantLock锁时(state值改变),它会将主内存中的数据刷新到自己的工作内存中(state值改变之后的所有对共享变量的读操作)。而当一个线程释放ReentrantLock锁时(state值改变),它会将自己工作内存中的数据刷新到主内存中(state值改变之前的所有对共享变量的写操作),这样其他线程就能够读取到最新的值。
备注:
volatile变量改变之后所有的共享变量读操作都会从主内存中重新获取最新值到工作内存,volatile变量改变之前的所有共享变量的改变都会刷新到主内存
一个自己写的测试类
import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;
class TestCache {
private volatile Boolean r=false;
private String string="1";
Thread readThread=null;
Thread writeThread=null;
/**
*
*/
@Test
void contextLoads() throws InterruptedException {
readThread=new Thread(()->{
while (true){
//下面的这2个if顺序说明了:volatile后的共享变量重新获取了,之前的不再重新获取
// if( r && string.contentEquals("2") ){//能看到string的变化
if( string.contentEquals("2") && r ){//不能看到string的变化
System.out.println("end task");
break;
}
}
});
writeThread=new Thread(()->{
string="2";
r=true;
});
readThread.start();
TimeUnit.SECONDS.sleep(2);
writeThread.start();
readThread.join();
}
}