方法一:为变量添加修饰:volatile(易变化关键字)
volatile static boolean isrun = true ;
这样做的目的是:加上volatile 的变量,每次循环都是只能在主存当中获取,不会从高速缓存区中获取!
测试结果:T1线程停止
方法二:使用synchronized
在Java内存模型中,synchronized规定,线程在加锁时, 先清空工作内存→在主内存中拷贝最新变量的副本到工作内存 →执行完代码→将更改后的共享变量的值刷新到主内存中→释放互斥锁。(线程获得对象锁后,会清空工作区内存,重新在主存中获取!)
可见性VS原子性
重点区分:volatile和synchronized ;
-
我们的volatile只能保证线程看到的变量是实时的,但是并不能保证是安全的!
-
多个线程同时访问,即使被volatile修饰,仍然可能会出现指令交错问题!
有序性
JVM会在不影响正确的条件下,调整语句的执行顺序!这种特性称作【指令重排】
//如下i和j的++操作调换顺序不影响结果!
public class ReSortTest {
static int i = 0 ;
static int j = 0 ;
public static void main(String[] args) {
i++; //修改为j++
j++; //修改为i++
}
}
思考:正常执行是正确的,而且多线程条件下指令重排可能是会出现问题的,为什么要进行指令重排的优化呢?
指令重排序优化
事实上,现代处理器会设计为一个时钟周期完成一条执行时间最长的CPU指令。为什么这么做呢?可以想到指令还可以再划分成一个个更小的阶段,例如,每条指令都可以分为: 取指令—指令译码—执行指令—内存访问—数据写回这5个阶段
重排之前:指令串行执行!
现代CPU支持多级指令流水线,例如支持同时执行取指令~指令译码–执行指令–内存访问–数据写回的处理器,就可以称之为五级指令流水线。这时CPU可以在一个时钟周期内,同时运行五条指令的不同阶段(相当于一条执行时间最长的复杂指令),IPC =1,本质上,流水线技术并不能缩短单条指令的执行时间,但它变相地提高了指令地吞吐率。
重拍之后:指令并行执行 !
总结:指令级别的优化,我们线程的不同指令的不同阶段可同时进行&#