java线程重排序问题

以前在看《java并发编程实战》的时候,看到重排序的时候始终不能很好理解,做了很多demo也未能实现书中所述效果,见CSDN上的提问

按作者的意思是,当线程A运行的时候,在没有同步或者使用锁的情况下,其他线程看到的线程A内的代码运行顺序可能被打乱。即后面的代码可能会先运行。

代码:

</pre>
public class NoVisibility {
private static boolean ready;
private static int     number;

private static class ReaderThread extends Thread {
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println(number);
}
}

public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
<pre>

ReaderThread线程可能会先看到主线程中ready=true。但是经过多次实验均未看到此效果。 今天偶然看到关于系统架构的文章,觉得可能问题出在系统的架构差异导致的。

从系统架构来看,目前的商用服务器大体可以分为三类,即对称多处理器结构 (SMP : Symmetric Multi-Processor) ,非一致存储访问结构 (NUMA : Non-Uniform Memory Access) ,以及海量并行处理结构 (MPP : Massive Parallel Processing)  本人DEMO运行环境为intel I3处理器. 在SMP系统架构中,所有的CPU共享全部资源,如总线,内存和I/O系统等,操作系统或管理数据库的复本只有一个,这种系统有一个最大的特点就是共享所有资源。多个CPU之间没有区别,平等地访问内存、外设、一个操作系统。操作系统管理着一个队列,每个处理器依次处理队列中的进程。此外SMP架构还存在内存屏障,保障指令的顺序执行。

本人运行环境是在intel I3处理器下运行的,估计此款CPU采用的就是SMP架构。

而在NUMA架构中,不同CPU之间具有独立的本地内存、 I/O 槽口等,CPU之间的通讯是通过互联模块 ( 如称为 Crossbar Switch) 进行连接和信息交互,因此每个 CPU 可以访问整个系统的内存 ( 这是 NUMA 系统与 MPP 系统的重要差别 ),这将导致在不同CPU通讯的时候,读取数据的CPU没有读到写CPU的实际数据。

另外除了CPU对指令的乱序执行外,编译器在编译的时候也可能会对代码进行重排序。CPU在乱序执行中对指令的执行顺序是不会打乱的,而只是可能不会等到前面的指令执行完在执行后面的指令,如同并发执行,相比于CPU的乱序,编译器的乱序才是真正对指令顺序做了调整。但是编译器的乱序也必须保证程序上下文的因果关系不发生改变。

本文只做笔记,关于重排序更深的理解还需对JVM内存模型,系统架构等做更深入研究

参考: SMP、NUMA、MPP体系结构介绍

中央处理器

为什么要指令重排序和屏障的作用

JAVA学习笔记–4.多线程编程 part1.背景知识和内存模型

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注