同步方法

原文: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

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

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

  1. public class SynchronizedCounter {
  2. private int c = 0;
  3. public synchronized void increment() {
  4. c++;
  5. }
  6. public synchronized void decrement() {
  7. c--;
  8. }
  9. public synchronized int value() {
  10. return c;
  11. }
  12. }

如果countSynchronizedCounter的实例,那么使这些方法同步有两个影响:

  • 首先,对同一对象的两个同步方法的调用不可能进行交错。当一个线程正在为对象执行同步方法时,所有其他线程调用同一对象的同步方法(暂停执行)直到第一个线程完成对象。
  • 其次,当同步方法退出时,它会自动与建立与同一对象的同步方法的任何后续调用之前发生的关系。这可以保证对所有线程都可以看到对象状态的更改。

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


Warning: When constructing an object that will be shared between threads, be very careful that a reference to the object does not “leak” prematurely. For example, suppose you want to maintain a List called instances containing every instance of class. You might be tempted to add the following line to your constructor:

  1. instances.add(this);

But then other threads can use instances to access the object before construction of the object is complete.


同步方法支持一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都是通过synchronized方法完成的。 (一个重要的例外:final字段,在构造对象后无法修改,可以通过非同步方法安全地读取,一旦构造了对象)这种策略是有效的,但可能会带来活跃度的问题,我们将在本课后面看到。