# 同步方法

Java 编程语言提供了两个基本的同步语法:synchronized 方法和 synchronized 语句。下一节将介绍两个同步语句的复杂度。这部分是关于同步的方法。

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

public class SynchronizedCounter {
    private int c = 0;

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

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

    public synchronized int value() {
        return c;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

如果 count 是一个 SynchronizedCounter 实例,那么使这些方法同步有两个效果:

  • 首先,同一对象上的两个同步方法的调用不可能进行交织。当一个线程正在执行一个对象的 synchronized 方法时, 调用同一个对象块的同步方法(挂起执行)的所有其他线程,直到第一个线程完成该对象。
  • 第二,当一个 synchronized 方法退出时,它会自动建立一个与之相关的同步方法的任何后续调用的发生关系。 这保证对对象的状态的更改对所有线程都是可见的。

请注意,构造函数无法同步 - 使用 synchronized 带有构造函数的关键字是语法错误。同步构造函数没有任何意义,因为创建对象的线程在构造时应该可以访问它。

警告: 构造一个将在线程之间共享的对象时,要非常小心,对对象的引用不会过早地“泄漏”。 例如,假设你想共享一个对象,其中有一个名为 instances 的 List 的属性。您可能会尝试将以下行添加到构造函数中:

instances.add(this);
1

但是其他的线程可以使用实例在对象构造完成访问对象。

同步方法是防止 线程干扰内存一致性错误 的一个简单的策略:如果一个对象对多个线程可见, 则对该对象变量的所有读取或写入都是通过 synchronized 方法完成的。(一个重要的例外:final 字段,对象被创建后不能修改,可以通过非同步的方法来安全地读)。 这种策略是有效的,但存在灵活性,稍后我们会讨论