03.原子性

原子性

所谓的原子性,就是一个或者多个操作在 CPU 执行的过程中不被中断的特性,CPU 能保证的原子操作是 CPU 指令级别的,而不是高级语言的操作符。我们在编程语言中部分看似原子操作的指令,在被编译到汇编之后往往会变成多个操作:

i++

# 编译成汇编之后就是:
# 读取当前变量 i 并把它赋值给一个临时寄存器;
movl i(%rip), %eax
# 给临时寄存器+1;
addl $1, %eax
# 把 eax 的新值写回内存
movl %eax, i(%rip)

我们可以清楚看到 C 代码只需要一句,但编译成汇编却需要三步(这里不考虑编译器优化,实际上通过编译器优化可以将这三条汇编指令合并成一条)。也就是说,只有简单的读取、赋值(而且必须是将数字赋值给某个变量,变量之间的相互赋值不是原子操作)才是原子操作。按照原子操作解决同步问题方式:依靠处理器原语支持把上述三条指令合三为一,当做一条指令来执行,保证在执行过程中不会被打断并且多线程并发也不会受到干扰。这样同步问题迎刃而解,这也就是所谓的原子操作。但处理器没有义务为任意代码片段提供原子性操作,尤其是我们的临界区资源十分庞大甚至大小不确定,处理器没有必要或是很难提供原子性支持,此时往往需要依赖于锁来保证原子性。

对应原子操作/事务在 Java 中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。Java 内存模型只保证了基本读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过 synchronized 和 Lock 来实现。由于 synchronized 和 Lock 能够保证任一时刻只有一个线程执行该代码块,那么自然就不存在原子性问题了,从而保证了原子性。

上一页
下一页