标签:实现 修改 处理器 rri volatil 等于 reads alpha out
学习材料来源于网络
如有侵权,联系删除
可见性问题:让一个线程对共享变量的修改,能够及时的被其他线程看到。
根据JMM中规定的happen before和同步原则:
对某个volatile字段的写操作 happens-before每个后续对该volatile字段的读操作。对volatile变量v的写入,与所有其他线程后续对v的读同步
要满足这些条件,所以volatile关键字就有这些功能:
1.禁止缓存;
volatile变量的访问控制符会加个ACC_VOLATILE
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.5
2.对volatile变量相关的指令不做重排序;
示例1
public class VisibilityDemo {
private volatile boolean flag = true;
public static void main(String[] args) throws InterruptedException {
VisibilityDemo visibilityDemo = new VisibilityDemo() ;
new Thread(new Runnable(){
@Override
public void run() {
int i = 0;
while (visibilityDemo.flag) {
i++;
}
System.out.println(i);
}
}).start() ;
TimeUnit. SECONDS. sleep( 2);
visibilityDemo.flag = false;
//设置is为false,使上面的线程结束wh ile循环demo1.flag = false;
System. out.println("被置为false了.");
}
}
一个字段或元素的更新不得与任何其他字段或元素的读取或更新交互。
特别是,分别更新字节数组的相邻元素的两个线程不得干涉或交互,也不需要同步以确保顺序一致性。
有些处理器(尤其是早期的Alphas处理器)没有提供写单个字节的功能。
在这样的处理器上更新 byte数组,若只是简单地读取整个内容,更新对应的字节,然后将整个内容再写回内存,将是不合法的。
这个问题有时候被称为“字分裂(word tearing)”,在单独更新单个字节有难度的处理器上,就需要寻求其它方式了。
基本不需要考虑这个,了解就好。
public class WordTearing extends Thread {
static final int LENGTH = 8;
static final int ITERS = 1000000;
static byte[] counts = new byte[LENGTH];
static Thread[] threads = new Thread[LENGTH];
final int id;
WordTearing(int i) {
id = i;
}
public void run() {
byte v = 0;
for (int i = 0; i < ITERS; i++) {
byte v2 = counts[id];
if (v != v2) {
System.err.println("Word-Tearing found: " +
"counts[" + id + "] = "+ v2 +
", should be " + v);
return;
}
v++;
counts[id] = v;
}
}
public static void main(String[] args) {
for (int i = 0; i < LENGTH; ++i)
(threads[i] = new WordTearing(i)).start();
}
}
虚拟机规范中,写64位的double和long分成了两次32位值的操作
由于不是原子操作,可能导致读取到某次写操作中64位的前32位,以及另外一次写操作的后32位
读写volatile 的 long和double总是原子的。读写引用也总是原子的
商业JVM不会存在这个问题,虽然规范没要求实现原子性,但是考虑到实际应用,大部分都实现了原子性。
标签:实现 修改 处理器 rri volatil 等于 reads alpha out
原文地址:https://www.cnblogs.com/shaoyayu/p/14073886.html