Synchronized Methods

Java 编程语言提供了两种基本的同步习惯用法:同步方法和同步语句。下一节将介绍两个同步语句中较复杂的一个。本节介绍同步方法。

要使方法同步,只需将synchronized关键字添加到其声明中:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

如果countSynchronizedCounter的实例,则使这些方法同步具有两个效果:

  • 首先,不可能对同一对象的两次同步方法调用进行交织。当一个线程正在为对象执行同步方法时,所有其他为同一对象块调用同步方法的线程(挂起执行),直到第一个线程对该对象完成。

  • 其次,当同步方法退出时,它会与随后对同一对象的同步方法的任何调用自动构建先发生关系。这样可以保证对对象状态的更改对所有线程都是可见的。

请注意,构造函数无法同步-将synchronized关键字与构造函数一起使用是语法错误。同步构造函数没有意义,因为只有创建对象的线程才可以在构造对象时访问它。

Warning:

构造将在线程之间共享的对象时,请务必小心不要对该对象的引用过早“泄漏”。例如,假设您要维护一个名为instancesList,其中包含类的每个实例。您可能会想将以下行添加到构造函数中:

instances.add(this);

但是,其他线程可以在对象的构造完成之前使用instances访问该对象。

同步方法提供了一种防止线程干扰和内存一致性错误的简单策略:如果一个对象对一个以上线程可见,则对该对象变量的所有读取或写入均通过synchronized方法完成。 (一个重要的 exception:final字段,在构造对象之后便无法修改,一旦构造了对象,就可以通过非同步方法安全地读取它)。此策略很有效,但可能会给liveness带来问题,因为我们将请参阅本类的稍后部分。