background image

Java 并发编程中出现的问题

线程之间共享数据引起了并发执行程序中的同步问题。那些数据是可能需要同步访问的呢?
很简单,线程之间能够共享的数据,也就是对多个线程可见的数据。
  Java 的数据有两种基本类型内存分配模式(不算虚拟机内部类型,详细内容参见虚
拟机规范):运行时栈和堆两种。由于运行时栈是线程所私有的,它主要用来保存局部变
量和中间运算结果,因此它们的数据是不可能被线程之间所共享的。内存堆是创建类对象
和数组地方,它们是被虚拟机内各个线程所共享的,因此如果一个线程能获得某个堆对
象的引用,那么就称这个对象是对该线程可见的。
  线程之间通信基本上通过共享对象引用来达到共享对象的简单类型字段和引用字段。
由于不涉及 I/O 操作,这种模式的共享比 IPC 共享要高效的多。但也使得两类错误成为可
能:线程干扰和内存一致性错误。防止此类问题发生的线程编程技术称作同步。我们详述
一下这两个错误的概念。
  线程干扰
  考察下面的一段代码:
1 class Counter {
2     private int c = 0;

4     public void increment() {
5         c++;
6     }

8     public void decrement() {
9         c--;
10     }
11 
12     public int value() {
13         return c;
14     }
15 
16 }
17 
18
  Counter 的目的是对 increment 方法的调用将 c 增加 1,对 decrement 的调用将 c
减去 1。然而如果一个 Counter 对象被多个线程所引用,那么这些线程之间的干扰就让我
们经常得不到期望的结果。
  当运行在不同线程中对同一对象进行访问的两个操作发生时,干扰就会产生。这是因
为这两个操作往往是由多步组成的,而且它们的执行顺序是可以互相交织的。
  表面看来,Counter 对象的 increment 和 decrement 操作是不可能交织的,每个