Java 线程的支持不是平台独立的
非常不幸,作为Java语言所保证的平台独立性最重要的组成部分-------Java线程,并非是平台独立的。这增加了实现不依赖于平台的线程系统的难度。在实现的时候,不得不考虑每个平台的细微区别,以确保你的程序在每个平台都保持一致。其实,写一个独立于平台的程序,还是有可能的,但必须非常小心。不过你可以放心,这个令人失望的事实,并不是Java的问题。(“Ace”Framework 就是一个非常好的,也非常复杂的平台独立线程系统http://www.cs.wustl.edu/~schmidt/ACE.html)。所以,在我继续讲下去之前,我不得不线讨论一下,由于平台的多样性,而导致的JVM的不一致性。
线程和进程(Threads and Processes)
第一个关键的系统级概念,究竟什么是线程或者说究竟什么是进程?她们其实就是操作系统内部的一种数据结构。
进程数据结构掌握着所有与内存相关的东西:全局地址空间、文件句柄等等诸如此类的东西。当一个进程放弃执行(准确的说是放弃占有CPU),而被操作系统交换到硬盘上,使别的进程有机会运行的时候,在那个进程里的所有数据也将被写到硬盘上,甚至包括整个系统的核心(core memory)。可以这么说,当你想到进程(process),就应该想到内存(memory) (进程 == 内存)。如上所述,切换进程的代价非常大,总有那么一大堆的内存要移来移去。你必须用秒这个单位来计量进程切换(上下文切换),对于用户来说秒意味着明显的等待和硬盘灯的狂闪(对于作者的我,就意味着IBM龙腾3代的烂掉,5555555)。言归正传,对于Java而言,JVM就几乎相当于一个进程(process),因为只有进程才能拥有堆内存(heap,也就是我们平时用new操作符,分出来的内存空间)。
那么线程是什么呢?你可以把它看成“一段代码的执行”---- 也就是一系列由JVM执行的二进制指令。这里面没有对象(Object)甚至没有方法(Method)的概念。指令执行的序列可以重叠,并且并行的执行。后面,我会更加详细的论述这个问题。但是请记住,线程是有序的指令,而不是方法(method)。
线程的数据结构,与进程相反,仅仅只包括执行这些指令的信息。它包含当前的运行上下文(context):如寄存器(register)的内容、当前指令的在运行引擎的指令流中的位置、保存方法(methods)本地参数和变量的运行时堆栈。如果发生线程切换,OS只需把寄存器的值压进栈,然后把线程包含的数据结构放到某个类是列表(LIST)的地方;把另一个线程的数据从列表中取出,并且用栈里的值重新设置寄存器。切换线程更加有效率,时间单位是毫秒。对于Java而言,一个线程可以看作是JVM的一个状态。
运行时堆栈(也就是前面说的存储本地变量和参数的地方)是线程数据结构一部分。这是因为多个线程,每一个都有自己的运行时堆栈,也就是说存储在这里面的数据是绝对线程安全(后面将会详细解释这个概念)的。因为可以肯定一个线程是无法修改另一个线程的系统级的数据结构的。也可以这么说一个不访问堆内存的(只读写堆栈内存)方法,是线程安全的(Thread Safe)。
线程安全和同步
线程安全,是指一个方法(method)可以在多线程的环境下安全的有效的访问进程级的数据(这些数据是与其他线程共享的)。事实上,线程安全是个很难达到的目标。
线程安全的核心概念就是同步,它保证多个线程:
l 同时开始执行,并行运行
l 不同时访问相同的对象实例
l 不同时执行同一段代码
我将会在后面的章节,一一细诉这些问题。但现在还是让我们来看看同步的一种经典的
实现方法——信号量。信号量是任何可以让两个线程为了同步它们的操作而相互通信的对象。






