解决多线程中内存可见性的方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013276277/article/details/81059865

    上一篇博客已经讲到了内存可见性问题,内存可见性所表现出来的问题就是失效数据,而有效规避这种问题的方法就是同步。本篇博客将告诉你具体采用哪些同步方式可以解决这类问题:加锁,volatile变量。

1、  加锁与可见性

    内置锁可以确保某个线程以一种可预测的方式来查看另一个进程的执行结果。看下面这张图,当线程A执行某个同步代码块时,线程B随后进入由同一个锁保护的同步代码块,在这种情况下可以保证,在锁被释放之前,A看到的变量值在B获得锁后同样可以由B看到。同样的,当线程B执行由锁保护的同步代码块时,可以看到线程A之前在同一个同步代码块中的所有操作结果。

    现在就可以理解:为什么在访问某个共享且可变的变量时要求所有线程在同一个锁上同步,就是为了确保某个线程写入该变量的值对于其他线程来说都是可见的。否则,如果一个线程在未持有正确锁的情况下读取某个变量,那么读到的可能是一个失效值。其实这边就需要你去理解加锁的真正含义是什么,注意:加锁的含义不仅是局限于互斥行为,还包括内存可见性,为了确保所有线程都能看到共享变量的最新值,所有执行读写操作的线程都要在同一个锁上同步。

2、  volatile变量

    java提供了一种轻量级的同步,就是volatile变量,用来确保将变量的更新操作通知都其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。Volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新的写入值。

    注意:在当前大多数处理器架构上,读取volatile变量的开销纸币读取非volatile变量的开销略高一写,但是并不意味着你可以肆意的使用volatile变量。在代码中依赖volatile变量来控制状态的可见性,通常比使用锁的代码更脆弱,也更难理解。仅当volatile变量能简化代码的实现以及同步策略的验证时,才应该是用他们。如果在验证正确性时需要对可见性进行复杂的判断,那么就不要使用volatile变量,volatile变量的正确使用场景包括:确保它们自身状态的可见性,确保它们所引用对象的状态的可见性,以及标识一些重要的程序生命周期事件的发生。

    对于一些需要先检查后执行的操作,可以使用volatile


猜你喜欢

转载自blog.csdn.net/u013276277/article/details/81059865