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

相关推荐
2301_780789664 小时前
跨平台适配!SDK 游戏盾兼容全终端游戏场景
java·网络·ddos
第九序言T5 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理
学长毕设5 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
步行cgn6 小时前
FormHttpMessageConverter 详解:Spring MVC 中表单数据的读写转换器
java·spring·mvc
龙亘川6 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
金銀銅鐵6 小时前
[Java] 用 CLI 展示 EnumMap 增删键值对时的内部变化
java·源码·ai编程
程序喵大人6 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型
秋天的怀念_David6 小时前
第二十二夜 · 数字迷雾
java·程序人生·算法
Raas1007 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
niucloud-admin7 小时前
NIUCLOUD PHP SAAS上门家政使用文档:城市管理
java·前端·php