JMM线程模型
记录JMM决定一个线程对共享变量的写入时,能对另一个线程可见。JMM定义了线程和主内存之间的关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。
每个单独的线程中存放了主内存的副本,那么说线程本地内存是什么时间点开始刷新的呢,其实这个时间是不固定的,刷新本地内存的时间是我们非常熟悉的LRU算法,也就是说要看共享变量的使用频率。
以下可以通过以下几种方式打破这种限制。
1. 使用volatile关键字,volatile关键字内部有个locak总线程锁,是这个东西保证了线程之间变量的原子性。
2. 使用synchronized加锁,或者其他加锁方式,内部原理是内存屏障
3. 使用缓存行的概念,一个缓存行占64字节
4. 让线程让出cpu执行片。
缓存行
缓存行使用示例:
public volatile long value = 0l;
public long p1,p2,p3,p4,p5,p6,p7;
当一个对象中有其他数据在频繁更新时,为了不影响其他行缓存行的刷新,则可利用缓存行的概念。
缓存行高效的原理:
如果你的X和y在同一块缓存行中,且两个字段都用volatile修饰了
那么将来两个线程再修改的时候,就需要将x和y发生修改的消息告诉另外一个线程,让它重新加载对应缓存,然而另外一个线程并没有使用该缓存行中对应的内容,只是因为缓存行读取的时候跟变量相邻,也会需要重新读取。这就会产生效率问题。
解决起来也简单,我们将数据中的两个volatile之间插入一些无用的内存,将第二个值挤出当前缓存行,那么执行的时候,就不会出现相应问题了。提高代码效率。
在JDK8中可以不用显示的声明一个缓存行,而可直接通过使用@Contented注解实现缓存行,但是需要开启-XX:-RestrictContended才能生效