指令重排序 as-if-serial

笔者认为看完一本书或刚要了解完一个知识点  最好自己先运行一些DEMO 自己尝试着去了解下各种意思  这样知识点最终一定是你的。靠死记硬背的讨论或简单的粗暴的看下资料 脑子里肯定还是一团浆糊。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; min-height: 15.0px }
p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #4e9072 }
p.p4 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #7e504f }
p.p5 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #777777 }
p.p6 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Monaco; color: #931a68 }
span.s1 { color: #931a68 }
span.s2 { text-decoration: underline }
span.s3 { color: #7e504f }
span.s4 { color: #000000 }
span.s5 { color: #0326cc }
span.s6 { color: #3933ff }
span.s7 { color: #91afcb }
span.Apple-tab-span { white-space: pre }

public class FinalDemo {

// FinalDemo finalDemo;

// public final String b;

//

// public FinalDemo() {

// Random rw = new Random();

// int p = rw.nextInt(10);

// b="helloWorld"+p;

// }

//

// public void write() {

//

// finalDemo=new FinalDemo();

// }

public void doMethodParam( Product product) {

//String obj=b;

// Random rw = new Random();

// int p = rw.nextInt(10);

Product totalMoney=product;

System.out.println("线程:"+Thread.currentThread().getName()+"----money:"+totalMoney.getMoney() + "-----------before---" );

System.out.println("线程:"+Thread.currentThread().getName()+"----money"+totalMoney.getMoney() + "-----------end---" );

}

@Test

public void testFinalMethodParam() {

Thread[] thread=new Thread[4];

for(int i=0;i<4;i++) {

thread[i] = new Thread(new Runnable() {

@Override

public void run() {

int a=new Random().nextInt(10);

// TODO Auto-generated method stub

Product product=new Product();

product.setName("name_"+a);

product.setMoney("10"+a);

doMethodParam(product);

}

});

thread[i].start();

}

}

class Product{

private String name;

private String money;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getMoney() {

return money;

}

public void setMoney(String money) {

this.money = money;

}

}

}

打印结果:

线程:Thread-0----money:8-----------before---

线程:Thread-2----money:9-----------before---

线程:Thread-2----money9-----------end---

线程:Thread-0----money8-----------end---

线程:Thread-1----money:8-----------before---

线程:Thread-3----money:5-----------before---

线程:Thread-1----money8-----------end---

线程:Thread-3----money5-----------end---

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px ".PingFang SC"; color: #454545 }
span.s1 { font: 12.0px "Helvetica Neue" }

从上述的打印结果  你看懂了什么。

总结如下:

1)上述中下行有两行before内容,并没有中规中矩的先before再end 说明了一个知识点:程序在执行过程中被指令重排序了。主要原因是编译器或处理器为了优化性能对指令序列进行排序的手段。

2)但是大家有没有观察到虽然表现为重排序 但同一个线程最终执行的结果是一样的,并不因为多线程的影响把值给改掉。这是因为JMM内存模型决定的。对于局部变量和方法参数都是线程私有的并不会被其他线程共享。

3)还有一点as-if-serial语义。不管怎么重排序 对于那种有依赖关系的单线程程序的执行结果不会被改变。处理器能保证对于有依赖关系的指令禁止重排序

时间: 2024-08-07 20:57:14

指令重排序 as-if-serial的相关文章

Java的多线程机制系列:不得不提的volatile及指令重排序(happen-before)

一.不得不提的volatile volatile是个很老的关键字,几乎伴随着JDK的诞生而诞生,我们都知道这个关键字,但又不太清楚什么时候会使用它:我们在JDK及开源框架中随处可见这个关键字,但并发专家又往往建议我们远离它.比如Thread这个很基础的类,其中很重要的线程状态字段,就是用volatile来修饰,见代码 /* Java thread status for tools, * initialized to indicate thread 'not yet started' */   p

J.U.C JMM. pipeline.指令重排序,happen-before(续)

前面已经介绍硬件平台Cache Coherence问题和解决办法,下面来看看Java虚拟机平台的相关知识.硬件平台处理器,高速缓存,主存之间的交互关系如下: Java内存模型(JMM)        Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model, JMM)来屏蔽掉底层各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果. 主内存和工作内存       Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟

深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则[转]

在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到锁机制,因此此小节中会适当引入锁的概念. 在Java Concurrency in Practice中是这样定义线程安全的: 当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替运行,并且不需要额外的同步及在调用方代码不必做其他的协调,这个类的行为仍然是正确的,那么这个类就是线程安全的. 显然只有资源竞争时才会导致线程不安全,因此无状态对象永远是线程安全的. 原子操作的描述是: 多个线程执行一个操作时,其

理解并发编程中的重要概念:指令重排序和指令乱序执行

看过了很多介绍指令重排序的文章,可惜由于自己硬件和计算机理论知识缺乏,很难理解深层次的奥秘和实现原理.不过也有很多帖子,讲的浅显易懂,使用的例子很形象.大牛就是能用简单的解释和通俗的比喻,给我们讲明白很高深的东西.这里做个摘抄和总结,和大家分享下,希望大家能够对指令重排序有个形象的认识,不至于在并发编程中犯一些简单的错误.如果理解有错误,希望看到的大神指正. 从源码变成可以被机器(或虚拟机)识别的程序,至少要经过编译期和运行期.重排序分为两类:编译期重排序和运行期重排序(乱序执行),分别对应编译

多线程之指令重排序

为什么会乱序 现在的CPU一般采用流水线来执行指令.一个指令的执行被分成:取指.译码.访存.执行.写回.等若干个阶段.然后,多条指令可以同时存在于流水线中,同时被执行. 指令流水线并不是串行的,并不会因为一个耗时很长的指令在"执行"阶段呆很长时间,而导致后续的指令都卡在"执行"之前的阶段上. 相反,流水线是并行的,多个指令可以同时处于同一个阶段,只要CPU内部相应的处理部件未被占满即可.比如说CPU有一个加法器和一个除法器,那么一条加法指令和一条除法指令就可能同时处

JVM并发机制的探讨——内存模型、内存可见性和指令重排序

[转]http://my.oschina.net/chihz/blog/58035 文章写的非常好,为作者点赞. JAVA内存模型 对于我们平时开发的业务应用来说,内存应该是访问速度最快的存储设备,对于频繁访问的数据,我们总是习惯把它们放到内存缓存中,有句话不是说么,缓存就像是清凉油,哪里有问题就抹一抹.但是CPU的运算速度比起内存的访问速度还要快几个量级,为了平衡这个差距,于是就专门为CPU引入了高速缓存,频繁使用的数据放到高速缓存当中,CPU在使用这些数据进行运算的时候就不必再去访问内存.但

关于volatile的可见性和禁止指令重排序的疑惑

在学习volatile语义的可见性和禁止指令重排序的相关测试中,发现并不能体现出禁止指令重排序的特性 实验代码如下 package com.aaron.beginner.multithread.volatiletest; import java.util.concurrent.CountDownLatch; /** * @author * @description 一句话描述该文件的用途 * @date 2017-03-01 */ public class VolatileAndNonVolat

深入浅出 Java Concurrency (4): 原子操作 part 3 指令重排序与happens-before法则

转: http://www.blogjava.net/xylz/archive/2010/07/03/325168.html 在这个小结里面重点讨论原子操作的原理和设计思想. 由于在下一个章节中会谈到锁机制,因此此小节中会适当引入锁的概念. 在Java Concurrency in Practice中是这样定义线程安全的: 当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替运行,并且不需要额外的同步及在调用方代码不必做其他的协调,这个类的行为仍然是正确的,那么这个类就是线程安

java指令重排序的问题

转载自于:http://my.oschina.net/004/blog/222069?fromerr=ER2mp62C 指令重排序是个比较复杂.觉得有些不可思议的问题,同样是先以例子开头(建议大家跑下例子,这是实实在在可以重现的,重排序的概率还是挺高的),有个感性的认识 /** * 一个简单的展示Happen-Before的例子. * 这里有两个共享变量:a和flag,初始值分别为0和false.在ThreadA中先给 a=1,然后flag=true. * 如果按照有序的话,那么在ThreadB