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,混合场景按需桥接;所有显式锁牢记"加锁必解锁",守住并发安全底线。

相关推荐
niceffking1 小时前
C++:initializer_list 与 {} 初始化的本质
开发语言·c++·cpp
jaysee-sjc1 小时前
十六、Java 网络编程全解析:UDP/TCP 通信 + BS/CS 架构
java·开发语言·网络·tcp/ip·算法·架构·udp
椎4951 小时前
SpringAI+DeepSeek大模型应用开发实战
java
江沉晚呤时1 小时前
基于 AssemblyLoadContext 的 .NET 插件化架构设计与实现
开发语言·c#·.net
独断万古他化2 小时前
【抽奖系统开发实战】Spring Boot 抽奖系统全链路总结:从架构到落地的实践复盘
java·spring boot·后端·架构·系列总结
编程之升级打怪2 小时前
简单的测试搜索词的分割算法思路
java·算法
码界奇点2 小时前
基于Spring MVC和MyBatis的妖气山视频管理系统设计与实现
java·spring·毕业设计·mvc·mybatis·源代码管理
2501_930707782 小时前
使用C#代码获取PDF文件的页数
开发语言·pdf·c#
东离与糖宝2 小时前
小米MiMo-V2-Pro开放调用,Java后端快速接入全流程实战
java·人工智能