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;
}
}
如果count
是SynchronizedCounter
的实例,则使这些方法同步具有两个效果:
-
首先,不可能对同一对象的两次同步方法调用进行交织。当一个线程正在为对象执行同步方法时,所有其他为同一对象块调用同步方法的线程(挂起执行),直到第一个线程对该对象完成。
-
其次,当同步方法退出时,它会与随后对同一对象的同步方法的任何调用自动构建先发生关系。这样可以保证对对象状态的更改对所有线程都是可见的。
请注意,构造函数无法同步-将synchronized
关键字与构造函数一起使用是语法错误。同步构造函数没有意义,因为只有创建对象的线程才可以在构造对象时访问它。
Warning:
构造将在线程之间共享的对象时,请务必小心不要对该对象的引用过早“泄漏”。例如,假设您要维护一个名为instances
的List
,其中包含类的每个实例。您可能会想将以下行添加到构造函数中:
instances.add(this);
但是,其他线程可以在对象的构造完成之前使用instances
访问该对象。
同步方法提供了一种防止线程干扰和内存一致性错误的简单策略:如果一个对象对一个以上线程可见,则对该对象变量的所有读取或写入均通过synchronized
方法完成。 (一个重要的 exception:final
字段,在构造对象之后便无法修改,一旦构造了对象,就可以通过非同步方法安全地读取它)。此策略很有效,但可能会给liveness带来问题,因为我们将请参阅本类的稍后部分。