多线程的问题
- 所见非所得
- 无法用肉眼检测程序的准确性
- 不同的运行平台有不同的表现
- 错误很难重现
可见性问题的学习
线程1 和线程2 去看一样的东西, 看上去不一样**
缓存,可能导致暂时的 可见性问题
重排序会导致永久的问题 ,最终使其死循环**
为什么所见非所得
JVM运行时数据区设计 , 多个内存 进行 ,有 公用的 ,私用的 ,之间交互 必然出现问题
这就是内存模型的又来 , 包含了一系列的规范
jre/bin/server 放置hsdis动态链接库
将运行模式设置为-server ,变成死循环
加关键字volatile
启动参数 -client
解决指令重排序导致的可见性的问题
调整设置解决问题
测试代码
package com.study.volatiletest;
import java.util.concurrent.TimeUnit;
// 1、 jre/bin/server 放置hsdis动态链接库
// 测试代码 将运行模式设置为-server, 变成死循环 。 没加默认就是client模式,就是正常(可见性问题)
// 2、 通过设置JVM的参数,打印出jit编译的内容 (这里说的编译非class文件),通过可视化工具jitwatch进行查看
// -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:LogFile=jit.log
// 关闭jit优化-Djava.compiler=NONE
public class VisibilityDemo {
private volatile boolean flag = true;//位于共享内存
public static void main(String[] args) throws InterruptedException {
VisibilityDemo demo1 = new VisibilityDemo();
Thread thread1 = new Thread(new Runnable() {
public void run() {
int i = 0;
// class -> 运行时jit编译 -> 汇编指令 -> 重排序
while (demo1.flag) { // 指令重排序
i++;
}
System.out.println(i);
}
});
thread1.start();
TimeUnit.SECONDS.sleep(2);
// 设置is为false,使上面的线程结束while循环
demo1.flag = false;
System.out.println("被置为false了.");
}
}
解释: 优化带来的弊端
优化后的伪代码
优化一种是如上图,另一种 变成汇编代码 用jitwatch查看
解决这个弊端的方法 : 内存模型(一种开发规范)
内存模型决定了在程序的每个点上可以读取什么值
private volatile boolean flag = true;
加的这个关键字的由来
volatile
Shared Variables 共享变量描述
线程之间共享的内存 叫 堆内存/共享内存 {实例 , 静态字段 ,数组 都在其中}
如果至少一次访问时写 , 那么 对同一个变量访问次(读/写) 是冲突的
规定
同步的规定
Happens-before先行发生原则
volatile关键字
final 在JMM中的处理
double和long的特殊处理
代码
import java.util.concurrent.TimeUnit;
public class VisibilityDemo1 {
// 状态标识
private static boolean is = true;
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
int i = 0;
while (VisibilityDemo1.is) {
synchronized (this) {
i++;
}
}
System.out.println(i);
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 设置is为false,使上面的线程结束while循环
VisibilityDemo1.is = false;
System.out.println("被置为false了.");
}
}
import java.util.concurrent.TimeUnit;
public class VisibilityDemo2 {
// 状态标识 (不用缓存)
private volatile boolean flag = true;
// 源码 -> 字节码class
// JVM 转化为 操作系统能够执行的代码 (JIT Just In Time Compiler 编译器 )(JVM -- client , --server)
public static void main(String[] args) throws InterruptedException {
VisibilityDemo2 demo1 = new VisibilityDemo2();
new Thread(new Runnable() {
public void run() {
int i = 0;
while (demo1.flag) {
i++;
}
System.out.println(i);
}
}).start();
TimeUnit.SECONDS.sleep(2);
// 设置is为false,使上面的线程结束while循环
demo1.flag = false;
System.out.println("被置为false了.");
}
}