Java 中的 synchronized 关键字(用法和示例)

2025 年 4 月 20 日 | 阅读 6 分钟

在 Java 中,synchronized 关键字提供了一种机制来控制多个线程对共享资源的访问。使用 synchronized 关键字,我们可以防止数据损坏和未经授权的访问。它为方法或代码块提供了一个,这样一次只有一个线程可以使用它。通过获取方法和代码块的锁,我们可以确保线程安全。

阅读更多 Java 中的同步

synchronized 关键字的用法

synchronized 关键字可以与方法代码块一起使用。当一个方法或代码块被声明为 synchronized 时,就会在指定的对象上获得一个锁,并且其他线程在锁被释放之前无法访问 synchronized 代码。

同步方法

当您希望确保一次只有一个线程可以访问整个方法时,可以使用同步方法。当方法修改共享资源(如类变量或数据结构)时,这很有用。

语法

同步方法示例

示例

编译并运行

输出

Counter: 2000

解释

在这个示例中,我们创建了一个 SynchronizedExample 类,其中包含一个实例变量 counter,我们希望以同步的方式对其进行递增。我们使用 synchronized 关键字定义了一个名为 increment() 的方法。这意味着一次只有一个线程可以执行此方法,从而确保以线程安全的方式递增 counter。

在 main 方法中,我们创建了两个线程,并将 lambda 表达式传递给 Thread 构造函数。每个 lambda 表达式都包含一个循环,通过调用 SynchronizedExample 对象的 increment() 方法来递增 counter。

我们使用 start() 方法启动两个线程,然后通过调用每个线程的 join() 方法来等待两个线程完成。最后,我们将 counter 的值打印到控制台。

输出表明,两个线程都成功地将 counter 分别递增了 1000 次,最终值为 2000。由于我们使用 synchronized 关键字确保一次只有一个线程执行 increment 方法,因此我们可以确信 counter 是以线程安全的方式递增的。

同步代码块

Java Synchronized 代码块可用于对方法中的任何特定资源执行同步。

阅读更多 Java 中的同步代码块

假设我们的方法中有 50 行代码,但我们只想同步 5 行;在这种情况下,我们可以使用同步代码块。如果我们把方法的所有代码都放在同步代码块中,它的效果将与同步方法相同。

语法

同步代码块示例

示例

编译并运行

输出

5 * 1 = 5
5 * 2 = 10
5 * 3 = 15
5 * 4 = 20
5 * 5 = 25
5 * 6 = 30
100 * 1 = 100
100 * 2 = 200
100 * 3 = 300
100 * 4 = 400
100 * 5 = 500
100 * 6 = 600

要记住的重要事项

  • 同步代码块用于锁定任何共享资源的某个对象。
  • 同步代码块的范围小于方法。
  • Java 同步代码块不允许多个 JVM 对共享资源提供访问控制。
  • 由于 synchronized 关键字的工作速度较慢,系统性能可能会下降。
  • Java 同步代码块比 Java 同步方法更有效。

synchronized 关键字还可以用于

  • 实例方法
  • 静态方法

同步实例方法

在实例方法上使用 synchronized,锁会在当前对象(this)上获取。如果多个线程使用同一个对象访问该方法,它们必须相互等待以释放锁。

语法

同步实例方法示例

示例

编译并运行

输出

1 2 3 4 5 6 7 8 9 10 
1 2 3 4 5 6 7 8 9 10 

静态同步

虽然同步方法可以确保一次只有一个线程可以访问它,但如果方法的操作不是顺序的,或者方法本身没有明确考虑执行顺序,它不能保证输出的顺序。

因此,为了保持同步行为,仅凭实例级别的锁是不够的;我们需要一个类级别的锁,这可以通过静态同步来实现。

例如,考虑以下场景。

假设一个类有多个静态同步方法(demo1、demo2、demo3、demo4),一个线程正在访问方法 demo1,那么此时其他线程无法访问其他静态同步方法。

阅读更多 Java 中的静态同步

语法

静态同步示例

示例

编译并运行

输出

Good Night: Mahi
Good Night: Mahi
Good Night: Mahi
Good Night: Mahi
Good Night: Sachin
Good Night: Sachin
Good Night: Sachin
Good Night: Sachin

Good Night: Mahi
Good Night: Mahi
Good Night: Mahi
Good Night: Mahi
Good Night: Sachin
Good Night: Sachin
Good Night: Sachin
Good Night: Sachin

要记住的重要事项

  • 线程安全:它确保一次只有一个线程可以访问同步代码块或方法,从而防止竞态条件。
  • 内部锁:Java 使用内部锁(也称为监视器锁)来管理同步。每个对象都有一个内部锁。
  • 静态同步:应用于静态方法时,锁应用于类对象,而不是实例。
  • 死锁:不当使用同步可能导致死锁,即两个或多个线程无限期地等待对方释放锁。
  • 性能影响:由于线程争用,同步可能会降低执行速度,因此应谨慎使用。
  • 线程间通信:它与 wait()、notify() 和 notifyAll() 等方法无缝配合,用于协调线程执行。
  • 同步方法会锁定整个方法。
  • 同步代码块允许我们仅锁定代码的特定部分,这可以提高性能。