Kotlin Mutex vs Java ReentrantLock vs synchronized

文档概述

本文档系统对比 JVM 生态中三种核心互斥锁机制:synchronized(JVM 内置线程锁)、java.util.concurrent.locks.ReentrantLock(Java 显式线程锁)、kotlinx.coroutines.sync.Mutex(Kotlin 协程锁),明确三者核心定位、特性差异、选型逻辑与实操规范。

一、核心概念与定位

锁类型 核心定位 所属体系 核心设计目标
synchronized JVM原生内置隐式锁,无需手动释放 Java 线程模型 极简实现线程级临界区互斥
ReentrantLock Java显式可重入锁,支持灵活高级特性 Java 线程模型 弥补synchronized功能局限,适配复杂线程并发
Mutex Kotlin协程专属互斥锁,挂起而非阻塞 Kotlin 协程模型 保留协程轻量级优势,实现协程级临界区互斥

核心本质区分 :synchronized/ReentrantLock 是线程级阻塞锁 ,加锁失败会阻塞整个线程,触发系统级上下文切换;Mutex 是协程级挂起锁,加锁失败仅挂起当前协程,线程可继续处理其他协程,资源利用率更高。

二、核心特性对比

特性维度 synchronized ReentrantLock Mutex
锁释放方式 隐式自动释放(JVM保证) 显式手动lock/unlock withLock自动释放,手动lock需finally解锁
公平锁支持 仅非公平,不可配置 支持,构造器可指定 支持,构造器可指定
超时/中断能力 不支持 支持超时获取、可中断加锁 支持超时获取,响应协程取消
重入性 支持 支持 支持
协程适配性 极差,阻塞线程废掉协程优势 差,同样阻塞线程 完美适配,纯挂起无阻塞
跨线程/协程使用 纯线程场景可用 全场景通用 非协程侧需runBlocking桥接

三、典型用法示例

1. synchronized 基础用法(Java)

java 复制代码
public class SynchronizedDemo {
    private int counter = 0;
    public void increment() {
        // 隐式加锁,代码块执行完毕自动释放
        synchronized (this) {
            counter++;
            System.out.println("当前值:" + counter);
        }
    }
    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();
        // 多线程并发调用
        for (int i = 0; i < 5; i++) {
            new Thread(demo::increment).start();
        }
    }
}

2. ReentrantLock 基础用法(Java,异常安全)

java 复制代码
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
    private int counter = 0;
    private final ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            counter++;
        } finally {
            lock.unlock(); // 必须finally释放,避免死锁
        }
    }
}

3. Mutex 基础用法(Kotlin协程)

kotlin 复制代码
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

var counter = 0
val mutex = Mutex()

fun main() = runBlocking {
    repeat(5) {
        launch(Dispatchers.Default) {
            // 自动加锁+解锁,异常安全,推荐写法
            mutex.withLock {
                counter++
                delay(10) // 协程挂起,线程不阻塞
            }
        }
    }
}

4. 跨协程+线程混用(Mutex+runBlocking)

kotlin 复制代码
// 非协程线程用runBlocking桥接,阻塞代价极低
Thread {
    Thread.sleep(100)
    runBlocking { mutex.withLock { counter++ } }
}.start()

四、总结

(一)选型

  • 纯Java多线程,简单短临界区 :选synchronized,代码极简,JVM自动管理,无额外心智负担。

  • 纯Java多线程,复杂需求 (超时、中断、公平锁):选ReentrantLock,功能灵活,可控性强。

  • Kotlin协程专属场景 :必选Mutex,完全适配协程,保留轻量级核心优势。

  • 协程+普通线程混合场景:临界区极短用Mutex+runBlocking;临界区较长直接用ReentrantLock,避免主线程阻塞。

(二)高频避坑与强制实践

  • 禁止协程内用synchronized/ReentrantLock:会阻塞线程,彻底丢失协程轻量级并发优势,属于核心禁忌。

  • 显式锁必须finally解锁:ReentrantLock和Mutex手动调用lock时,务必在finally块解锁,杜绝死锁。

  • Mutex禁止非协程直接调用:挂起函数只能在协程内执行,非协程侧必须用runBlocking包裹。

  • 锁粒度尽量细:只包裹共享资源操作代码,缩短锁持有时间,提升并发效率。

  • 慎用公平锁:公平锁性能更低,仅在严格要求执行顺序时使用,默认用非公平锁即可。

线程并发看场景:简单用synchronized,复杂用ReentrantLock;协程并发只选Mutex,混合场景按需桥接;所有显式锁牢记"加锁必解锁",守住并发安全底线。

相关推荐
云烟成雨TD1 天前
Spring AI Alibaba 1.x 系列【6】ReactAgent 同步执行 & 流式执行
java·人工智能·spring
Wenweno0o1 天前
0基础Go语言Eino框架智能体实战-chatModel
开发语言·后端·golang
于慨1 天前
Lambda 表达式、方法引用(Method Reference)语法
java·前端·servlet
swg3213211 天前
Spring Boot 3.X Oauth2 认证服务与资源服务
java·spring boot·后端
gelald1 天前
SpringBoot - 自动配置原理
java·spring boot·后端
殷紫川1 天前
深入理解 AQS:从架构到实现,解锁 Java 并发编程的核心密钥
java
一轮弯弯的明月1 天前
贝尔数求集合划分方案总数
java·笔记·蓝桥杯·学习心得
chenjingming6661 天前
jmeter线程组设置以及串行和并行设置
java·开发语言·jmeter
殷紫川1 天前
深入拆解 Java volatile:从内存屏障到无锁编程的实战指南
java
eddieHoo1 天前
查看 Tomcat 的堆内存参数
java·tomcat