掘金 后端 ( ) • 2024-04-03 10:51

theme: juejin

是什么

是一个关键字,用于在多线程环境下实现同步,以控制对共享资源的并发访问。它可以保证在同一时刻,只有一个线程可以执行某个方法或代码块。 特点:

  • 可重入:Java的Synchronized锁是可重入的,这意味着同一个线程可以多次获取同一个锁。这避免了在递归调用或者一个线程在已持有锁的情况下再次请求锁时产生死锁的情况。
  • 不可中断:一旦线程获取了锁,其他线程就只能等待锁被释放。等待获取锁的线程不能被中断。
  • 无公平性:Synchronized锁不保证等待锁的线程会按照请求锁的顺序获得锁。这意味着不保证等待时间最长的线程会首先获得锁。

使用场景

  1. 同步实例方法:锁住的是调用该方法的对象实例。
public synchronized void method() {
    // 方法体# 是什么
是一个关键字,用于在多线程环境下实现同步,以控制对共享资源的并发访问。它可以保证在同一时刻,只有一个线程可以执行某个方法或代码块。
特点:

- **可重入**:Java的Synchronized锁是可重入的,这意味着同一个线程可以多次获取同一个锁。这避免了在递归调用或者一个线程在已持有锁的情况下再次请求锁时产生死锁的情况。
- **不可中断**:一旦线程获取了锁,其他线程就只能等待锁被释放。等待获取锁的线程不能被中断。
- **无公平性**:Synchronized锁不保证等待锁的线程会按照请求锁的顺序获得锁。这意味着不保证等待时间最长的线程会首先获得锁。

# 使用场景

1. 同步实例方法:锁住的是调用该方法的对象实例。
```java
public synchronized void method() {
    // 方法体
}
  1. 同步静态方法:锁住的是这个类的所有实例,使用Class对象作为锁。
public static synchronized void staticMethod() {
    // 方法体
}
  1. 同步代码块:指定锁对象,锁住的是括号里面的对象。
private final Object lock = new Object();
public void blockMethod() {
    synchronized(lock) {
        // 代码块
    }
}

使用建议:

  • 尽量避免将整个方法体都同步,如果可能,仅同步必要的代码段。
  • 考虑使用java.util.concurrent.locks包中的锁,它提供了更加灵活的锁操作,包括可中断锁、可轮询锁以及定时锁等。

优缺点

**优点:**Synchronized提供了一种锁的机制,能够确保代码段的原子性、可见性和有序性。 缺点:

  • **性能开销:**每次进入和退出同步块时都需要进行锁的获取和释放操作
  • **死锁风险:**不当的使用Synchronized(如在多个线程间相互等待锁)可能导致死锁,使得程序陷入停滞状态。
  • 不具备锁的灵活性:Synchronized只有非公平的重入锁,没有读写锁、公平锁等更复杂的锁类型,也缺少尝试获取锁和定时锁等功能。

Java中对Synchronized的优化:

  1. 锁粗化:如果JVM检测到一系列的连续锁操作实际上是无间断的,那么JVM会将这些操作合并为一次更长时间的锁操作,减少锁获取和释放的次数。
  2. 锁消除:JVM通过逃逸分析来检测到某些锁对象只能被一个线程访问,那么JVM会消除这些锁操作,因为它们实际上不是共享的。
  3. 偏向锁:是一种锁优化技术,它假设锁主要被一个线程持有。当一个线程获取了偏向锁,再次进入同步块时不需要进行同步。偏向锁可以通过避免不必要的锁竞争来提高性能。
  4. 轻量级锁:当锁是偏向锁(Biased Locking)不可用时,JVM会尝试使用轻量级锁。轻量级锁通过在对象头中存储锁定线程的标识来避免使用重量级的操作系统互斥锁。
  5. 自旋锁:在某些情况下,当线程尝试获取锁但失败时,JVM会让线程“自旋”(即在不放弃CPU时间片的情况下循环等待),以期待锁很快被释放。这可以避免线程挂起和唤醒的开销,适用于锁占用时间非常短的情况。

内部实现

Java中的synchronized实现依赖于JVM底层的监视器锁(Monitor Lock),监视器锁是依赖底层操作系统的Mutex实现的。监视器锁是利用对象头中的一部分数据来实现的。对象头包含了对象的hash码、分代年龄以及锁标记等信息。(不管是锁调用该方法的对象,还是锁Class对象,都是锁对象) synchronized使用的监视器锁可以处于以下几种状态: 无锁状态:对象未被锁定。 偏向锁状态:假设一个线程会再次获得锁,避免了锁的竞争。 轻量级锁状态:当没有竞争出现时,通过CAS操作避免使用重量级的操作系统互斥量。 重量级锁状态:当有多个线程竞争同一个锁时,锁会升级为重量级锁,此时会使用操作系统的互斥量来管理线程的同步。 锁升级过程: 为了减少获取和释放监视器锁的开销,JVM采用了锁升级的优化策略: 偏向锁:当一个synchronized块首次被线程进入时,JVM会将锁标志设置为偏向锁,并将线程ID记录在对象头中。再次进入时,只需检查线程ID即可进入。 轻量级锁:当有另一个线程尝试获取同一个偏向锁时,偏向锁会升级为轻量级锁。线程会在自己的栈帧中创建锁记录(Lock Record),尝试通过CAS操作将对象头指向锁记录。 重量级锁:如果轻量级锁的CAS操作失败,表示有竞争存在,锁会升级为重量级锁。此时,线程可能会被挂起,直到锁被释放。

名词补充

Class对象:Class对象是反映类本身特征的对象。每个类被加载到JVM(Java虚拟机)时,JVM会为该类自动创建一个唯一的Class对象。通过这个对象,你可以获取到类的元数据信息,包括类的名称、方法、变量、注解等,以及进行反射操作,如创建类的实例、获取和设置类成员的值等。

} 2. 同步静态方法:锁住的是这个类的所有实例,使用Class对象作为锁。

是什么

是一个关键字,用于在多线程环境下实现同步,以控制对共享资源的并发访问。它可以保证在同一时刻,只有一个线程可以执行某个方法或代码块。
特点:

  • 可重入:Java的Synchronized锁是可重入的,这意味着同一个线程可以多次获取同一个锁。这避免了在递归调用或者一个线程在已持有锁的情况下再次请求锁时产生死锁的情况。
  • 不可中断:一旦线程获取了锁,其他线程就只能等待锁被释放。等待获取锁的线程不能被中断。
  • 无公平性:Synchronized锁不保证等待锁的线程会按照请求锁的顺序获得锁。这意味着不保证等待时间最长的线程会首先获得锁。

使用场景

  1. 同步实例方法:锁住的是调用该方法的对象实例。
public synchronized void method() {
    // 方法体
}
  1. 同步静态方法:锁住的是这个类的所有实例,使用Class对象作为锁。
public static synchronized void staticMethod() {
    // 方法体
}
  1. 同步代码块:指定锁对象,锁住的是括号里面的对象。
private final Object lock = new Object();
public void blockMethod() {
    synchronized(lock) {
        // 代码块
    }
}

使用建议:

  • 尽量避免将整个方法体都同步,如果可能,仅同步必要的代码段。
  • 考虑使用java.util.concurrent.locks包中的锁,它提供了更加灵活的锁操作,包括可中断锁、可轮询锁以及定时锁等。

优缺点

**优点:**Synchronized提供了一种锁的机制,能够确保代码段的原子性、可见性和有序性。
缺点:

  • **性能开销:**每次进入和退出同步块时都需要进行锁的获取和释放操作
  • **死锁风险:**不当的使用Synchronized(如在多个线程间相互等待锁)可能导致死锁,使得程序陷入停滞状态。
  • 不具备锁的灵活性:Synchronized只有非公平的重入锁,没有读写锁、公平锁等更复杂的锁类型,也缺少尝试获取锁和定时锁等功能。

Java中对Synchronized的优化:

  1. 锁粗化:如果JVM检测到一系列的连续锁操作实际上是无间断的,那么JVM会将这些操作合并为一次更长时间的锁操作,减少锁获取和释放的次数。
  2. 锁消除:JVM通过逃逸分析来检测到某些锁对象只能被一个线程访问,那么JVM会消除这些锁操作,因为它们实际上不是共享的。
  3. 偏向锁:是一种锁优化技术,它假设锁主要被一个线程持有。当一个线程获取了偏向锁,再次进入同步块时不需要进行同步。偏向锁可以通过避免不必要的锁竞争来提高性能。
  4. 轻量级锁:当锁是偏向锁(Biased Locking)不可用时,JVM会尝试使用轻量级锁。轻量级锁通过在对象头中存储锁定线程的标识来避免使用重量级的操作系统互斥锁。
  5. 自旋锁:在某些情况下,当线程尝试获取锁但失败时,JVM会让线程“自旋”(即在不放弃CPU时间片的情况下循环等待),以期待锁很快被释放。这可以避免线程挂起和唤醒的开销,适用于锁占用时间非常短的情况。

内部实现

Java中的synchronized实现依赖于JVM底层的监视器锁(Monitor Lock),监视器锁是依赖底层操作系统的Mutex实现的。监视器锁是利用对象头中的一部分数据来实现的。对象头包含了对象的hash码、分代年龄以及锁标记等信息。(不管是锁调用该方法的对象,还是锁Class对象,都是锁对象)
synchronized使用的监视器锁可以处于以下几种状态:
无锁状态:对象未被锁定。
偏向锁状态:假设一个线程会再次获得锁,避免了锁的竞争。
轻量级锁状态:当没有竞争出现时,通过CAS操作避免使用重量级的操作系统互斥量。
重量级锁状态:当有多个线程竞争同一个锁时,锁会升级为重量级锁,此时会使用操作系统的互斥量来管理线程的同步。
锁升级过程:
为了减少获取和释放监视器锁的开销,JVM采用了锁升级的优化策略:
偏向锁:当一个synchronized块首次被线程进入时,JVM会将锁标志设置为偏向锁,并将线程ID记录在对象头中。再次进入时,只需检查线程ID即可进入。
轻量级锁:当有另一个线程尝试获取同一个偏向锁时,偏向锁会升级为轻量级锁。线程会在自己的栈帧中创建锁记录(Lock Record),尝试通过CAS操作将对象头指向锁记录。
重量级锁:如果轻量级锁的CAS操作失败,表示有竞争存在,锁会升级为重量级锁。此时,线程可能会被挂起,直到锁被释放。

名词补充

Class对象:Class对象是反映类本身特征的对象。每个类被加载到JVM(Java虚拟机)时,JVM会为该类自动创建一个唯一的Class对象。通过这个对象,你可以获取到类的元数据信息,包括类的名称、方法、变量、注解等,以及进行反射操作,如创建类的实例、获取和设置类成员的值等。

public static synchronized void staticMethod() {
    // 方法体
}
  1. 同步代码块:指定锁对象,锁住的是括号里面的对象。
private final Object lock = new Object();
public void blockMethod() {
    synchronized(lock) {
        // 代码块
    }
}

使用建议:

  • 尽量避免将整个方法体都同步,如果可能,仅同步必要的代码段。
  • 考虑使用java.util.concurrent.locks包中的锁,它提供了更加灵活的锁操作,包括可中断锁、可轮询锁以及定时锁等。

优缺点

**优点:**Synchronized提供了一种锁的机制,能够确保代码段的原子性、可见性和有序性。 缺点:

  • **性能开销:**每次进入和退出同步块时都需要进行锁的获取和释放操作
  • **死锁风险:**不当的使用Synchronized(如在多个线程间相互等待锁)可能导致死锁,使得程序陷入停滞状态。
  • 不具备锁的灵活性:Synchronized只有非公平的重入锁,没有读写锁、公平锁等更复杂的锁类型,也缺少尝试获取锁和定时锁等功能。

Java中对Synchronized的优化:

  1. 锁粗化:如果JVM检测到一系列的连续锁操作实际上是无间断的,那么JVM会将这些操作合并为一次更长时间的锁操作,减少锁获取和释放的次数。
  2. 锁消除:JVM通过逃逸分析来检测到某些锁对象只能被一个线程访问,那么JVM会消除这些锁操作,因为它们实际上不是共享的。
  3. 偏向锁:是一种锁优化技术,它假设锁主要被一个线程持有。当一个线程获取了偏向锁,再次进入同步块时不需要进行同步。偏向锁可以通过避免不必要的锁竞争来提高性能。
  4. 轻量级锁:当锁是偏向锁(Biased Locking)不可用时,JVM会尝试使用轻量级锁。轻量级锁通过在对象头中存储锁定线程的标识来避免使用重量级的操作系统互斥锁。
  5. 自旋锁:在某些情况下,当线程尝试获取锁但失败时,JVM会让线程“自旋”(即在不放弃CPU时间片的情况下循环等待),以期待锁很快被释放。这可以避免线程挂起和唤醒的开销,适用于锁占用时间非常短的情况。

内部实现

Java中的synchronized实现依赖于JVM底层的监视器锁(Monitor Lock),监视器锁是依赖底层操作系统的Mutex实现的。监视器锁是利用对象头中的一部分数据来实现的。对象头包含了对象的hash码、分代年龄以及锁标记等信息。(不管是锁调用该方法的对象,还是锁Class对象,都是锁对象) synchronized使用的监视器锁可以处于以下几种状态: 无锁状态:对象未被锁定。 偏向锁状态:假设一个线程会再次获得锁,避免了锁的竞争。 轻量级锁状态:当没有竞争出现时,通过CAS操作避免使用重量级的操作系统互斥量。 重量级锁状态:当有多个线程竞争同一个锁时,锁会升级为重量级锁,此时会使用操作系统的互斥量来管理线程的同步。 锁升级过程: 为了减少获取和释放监视器锁的开销,JVM采用了锁升级的优化策略: 偏向锁:当一个synchronized块首次被线程进入时,JVM会将锁标志设置为偏向锁,并将线程ID记录在对象头中。再次进入时,只需检查线程ID即可进入。 轻量级锁:当有另一个线程尝试获取同一个偏向锁时,偏向锁会升级为轻量级锁。线程会在自己的栈帧中创建锁记录(Lock Record),尝试通过CAS操作将对象头指向锁记录。 重量级锁:如果轻量级锁的CAS操作失败,表示有竞争存在,锁会升级为重量级锁。此时,线程可能会被挂起,直到锁被释放。

名词补充

Class对象:Class对象是反映类本身特征的对象。每个类被加载到JVM(Java虚拟机)时,JVM会为该类自动创建一个唯一的Class对象。通过这个对象,你可以获取到类的元数据信息,包括类的名称、方法、变量、注解等,以及进行反射操作,如创建类的实例、获取和设置类成员的值等。