synchronized关键字的基本概念

在Java多线程编程中,synchronized关键字用于实现线程同步,确保多个线程在访问共享资源时的互斥性。它可以修饰方法或代码块,保证同一时刻只有一个线程执行该段代码。

public synchronized void method() {}
public void method() { synchronized(obj) {} }

synchronized的三种使用方式

修饰实例方法
锁住当前对象实例,进入同步方法前需获得当前实例的锁。

public synchronized void increment() {
    // 线程安全代码
}

修饰静态方法
锁住当前类的Class对象,作用于类的所有实例。

public static synchronized void staticMethod() {
    // 线程安全代码
}

同步代码块
可以指定锁对象,提供更细粒度的控制。

public void method() {
    synchronized(lockObject) {
        // 线程安全代码
    }
}

synchronized的底层实现原理

JVM通过**Monitor(管程)**实现synchronized的同步机制。每个Java对象都与一个Monitor相关联,包含以下关键字段:

  • Owner:持有锁的线程
  • EntryList:竞争锁的线程队列
  • WaitSet:调用wait()后进入等待的线程集合

同步代码块使用monitorentermonitorexit字节码指令实现加锁/解锁,方法同步通过方法表中的ACC_SYNCHRONIZED标志实现。

锁升级过程

JDK1.6后引入锁优化机制,锁状态会随竞争情况升级:

  1. 无锁状态:初始状态
  2. 偏向锁:消除无竞争情况下的同步开销
  3. 轻量级锁:使用CAS自旋替代阻塞
  4. 重量级锁:真正的互斥锁

升级过程不可逆,适应不同并发场景的性能需求。

使用注意事项

死锁风险
多个线程互相持有对方需要的锁时会导致死锁。典型条件包括:

  • 互斥条件
  • 请求与保持条件
  • 不剥夺条件
  • 环路等待条件
// 典型死锁示例
Thread1: lockA -> try lockB  
Thread2: lockB -> try lockA

性能影响
过度使用会导致:

  • 线程上下文切换开销
  • 降低并发度
  • 锁竞争激烈时性能下降

最佳实践建议

  1. 尽量减小同步范围,使用代码块而非方法同步
  2. 避免在同步块内调用外部方法(容易引发死锁)
  3. 对读写差异大的场景考虑读写锁(ReentrantReadWriteLock)
  4. 高并发场景可评估CAS乐观锁替代方案

与Lock接口的对比

| 特性 | synchronized | Lock | |--------------------|--------------------|--------------------| | 获取方式 | 自动获取释放 | 需显式调用 | | 锁类型 | 不可中断 | 可中断 | | 公平性 | 非公平 | 可配置公平性 | | 条件变量 | 单一wait/notify | 多Condition支持 | | 性能 | JDK优化后差异缩小 | 特定场景更灵活 |

通过合理使用synchronized关键字,可以在保证线程安全的同时平衡系统性能,是Java并发编程的基础构建块之一。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐