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

相关推荐
Scott9999HH1 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔1 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海2 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨3 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区5 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大6 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai6 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说6 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json