Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • MacOS
  • Linux
  • Windows
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • MacOS
  • Linux
  • Windows
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java基础

    • Java概述
    • Java语法
    • 面向对象编程
    • Java数组
    • String字符串
    • 异常处理
  • Java集合

    • Java集合概述
    • ArrayList
    • LinkedList
    • HashMap
    • LinkedHashMap
    • HashSet
    • TreeMap
    • Queue&Deque
  • Java并发

    • Java并发概述
    • 线程与进程
    • Thread类与线程生命周期
    • 线程安全
    • synchronized关键字
      • 1. synchronized 的基本概念
      • 2. synchronized 的使用方式
        • 2.1 修饰实例方法
        • 2.2 修饰静态方法
        • 2.3 修饰代码块
      • 3. synchronized 的锁对象
      • 4. synchronized 的底层实现
      • 5. synchronized 与 ReentrantLock 的比较
      • 6. synchronized 的优缺点
      • 7. 适用场景
      • 8. 总结
    • volatile关键字
    • Java内存模型(JMM)
    • 线程间通信
    • 线程池
    • 并发工具类
    • 原子操作类Atomic
    • 并发锁
    • 并发容器
    • ConcurrentHashMap
    • BlockingQueue
    • CopyOnWriteArrayList
    • ThreadLocal
    • Fork/Join框架
    • ScheduledThreadPoolExecutor
    • CompletableFuture
  • Java IO

    • Java IO概述
  • JVM

    • JVM概述
  • Java
  • Java并发
Wray
2024-10-31
目录

synchronized关键字

synchronized 关键字是 Java 中用于实现线程同步的核心机制之一,它用于确保多个线程对共享资源的访问是互斥的,从而避免线程安全问题。

# 1. synchronized 的基本概念

  • 互斥锁:synchronized 关键字可以用于方法或代码块,保证同一时间只有一个线程可以执行被保护的代码,从而实现对共享资源的互斥访问。
  • 内置锁:每个 Java 对象都有一个内置的锁(Monitor),synchronized 利用这个内置锁来控制线程的访问。

# 2. synchronized 的使用方式

synchronized 可以用来修饰方法和代码块,下面分别进行详细说明。

# 2.1 修饰实例方法

  • 实例方法加锁:
    public synchronized void increment() {
        count++;
    }
    
    • 当一个线程调用 increment() 方法时,其他线程将无法调用该对象的任何其他 synchronized 方法。
    • 锁的对象是当前实例 (this),即同一实例对象的多个线程在调用同步方法时是互斥的。

# 2.2 修饰静态方法

  • 静态方法加锁:
    public static synchronized void print() {
        System.out.println("Static method");
    }
    
    • 锁的对象是类的 Class 对象 (ClassName.class),即针对所有该类的实例共享同一把锁。
    • 保证同一类的多个线程在调用 synchronized 静态方法时是互斥的。

# 2.3 修饰代码块

  • 同步代码块:
    public void increment() {
        synchronized (this) {
            count++;
        }
    }
    
    • 可以在方法内部使用 synchronized 关键字包裹部分代码,减少锁的粒度,从而提高程序的并发性。
    • 可以对不同的对象加锁,比如 synchronized (lock),灵活控制同步的范围。

# 3. synchronized 的锁对象

synchronized 使用的锁对象可以是当前实例 (this)、类的 Class 对象 (ClassName.class)、或者是其他任意的对象。

  • 对象锁:修饰实例方法或代码块,锁住的是当前对象,线程进入 synchronized 方法或代码块之前必须获得对象的锁。
  • 类锁:修饰静态方法,锁住的是类的 Class 对象,保证该类的所有实例在访问同步静态方法时是互斥的。
  • 自定义对象锁:通过同步代码块对某个特定对象加锁,可以灵活控制锁的粒度。例如:
    private final Object lock = new Object();
    public void performTask() {
        synchronized (lock) {
            // 代码逻辑
        }
    }
    

静态方法加锁的锁和实例方法加锁的锁是不同的:

  • 静态同步方法锁住的是类级别的 Class 对象。
  • 实例同步方法锁住的是具体对象级别的锁(即 this)。

因此,锁住静态方法并不会阻止其他线程访问实例方法,两个线程可以同时执行一个实例的 synchronized 实例方法和该类的 synchronized 静态方法,因为它们锁住的是不同的对象。

# 4. synchronized 的底层实现

synchronized 的底层是通过进入和退出对象的 Monitor(监视器)来实现的,JVM 使用 monitorenter 和 monitorexit 指令来保证同步行为。

  • Monitor:Monitor 是一个同步工具,可以理解为一个重量级锁。在进入 synchronized 方法或代码块时,线程会获取 Monitor,退出时会释放 Monitor。
  • 偏向锁、轻量级锁和重量级锁:JVM 对 synchronized 的实现进行了优化,引入了偏向锁、轻量级锁和重量级锁来减少获取锁的开销,以提高性能。
    • 偏向锁:当一个线程多次获得同一个锁时,JVM 会将该锁偏向于这个线程,从而减少同步开销。
    • 轻量级锁:当偏向锁被其他线程争夺时,会升级为轻量级锁。
    • 重量级锁:当多个线程竞争激烈时,锁会升级为重量级锁,阻塞其他线程。

# 5. synchronized 与 ReentrantLock 的比较

  • 可重入性:synchronized 是可重入锁,意味着同一个线程可以多次获得同一把锁而不会发生死锁。例如,一个 synchronized 方法调用另一个 synchronized 方法时,线程不会被阻塞。
  • 是否公平:synchronized 是非公平锁,不能保证线程获取锁的顺序。而 ReentrantLock 可以设置为公平锁,以保证等待时间最长的线程优先获得锁。
  • 灵活性:ReentrantLock 提供了更多灵活的功能,例如可以尝试获取锁、可中断锁等待、支持多个条件变量等。而 synchronized 相对较为简单,不具备这些功能。
  • 性能:在 Java 早期版本中,synchronized 的性能相对较低,但在 JDK 1.6 之后,对 synchronized 进行了大量优化,其性能与 ReentrantLock 相差无几。

# 6. synchronized 的优缺点

  • 优点:
    • 语法简单,易于使用和理解。
    • JVM 会自动管理锁的获取和释放,不容易出错。
  • 缺点:
    • 同步范围大时,可能会导致较高的性能开销。
    • synchronized 是非公平的,可能导致某些线程长期得不到锁,发生饥饿现象。
    • 没有提供显式的锁控制,功能相对较弱。

# 7. 适用场景

  • 简单的同步场景:当需要对共享资源进行简单的线程同步操作时,使用 synchronized 是最为直接和便捷的选择。
  • 多线程访问共享对象:适用于保护方法或代码块,保证同一时间只有一个线程可以执行,避免竞态条件的发生。

# 8. 总结

synchronized 关键字是 Java 并发编程中的重要工具之一,用于确保线程对共享资源的互斥访问。它使用 Java 的内置锁来管理线程的同步,通过保证方法或代码块在同一时间只能被一个线程执行,从而避免数据不一致的问题。尽管 synchronized 的功能相对简单,但在很多场景下,它是实现线程安全的首选方式。理解 synchronized 的底层机制和应用场景,有助于编写高效且健壮的多线程程序。

上次更新: 2024/11/01, 13:45:14
线程安全
volatile关键字

← 线程安全 volatile关键字→

Copyright © 2023-2024 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式