11.1.5 原子操作
在介绍代码清单11-1中的IdGenerator类的getNext方法时提到过,Java代码中的一条语句,可能实际上对应的是多条字节代码指令。CPU在一条指令的执行过程中不会进行线程调度和上下文切换,但是在两条指令的执行间隙,可能发生线程切换。如果代码清单11-1中的“value++”语句由一条CPU指令来完成,就不存在多线程访问时可能出现的问题。
在Java中,对于非long型和double型的域的读取和写入操作是原子操作。对象引用的读取和写入操作也是原子操作。比如读取一个int类型的域时,该域对应的内存地址中的32位的内容会被完整地读取,在读取过程中不会被其他线程所打断。在进行写入操作时也不会被打断。在写入非volatile的long型和double型的域的值时,分成两次操作来完成。一个long型或double型的域的长度是64位,每次写入32位。在一个线程写入了long型或double型的域的前32位之后,在写入后32位之前,另外一个线程有可能访问这个域的值,从而读取只完成部分写入操作的错误值。因此在多线程程序中使用long型和double型的共享变量时,需要把变量声明为volatile,以保证读取和写入操作的完整性。