当前位置: 首页 > news >正文

Java 锁机制详解:用“厕所门”和“防盗门”轻松理解多线程同步

Java 锁机制详解:用“厕所门”和“防盗门”轻松理解多线程同步

目录

  • 锁的作用
  • synchronized 关键字
  • ReentrantLock
  • ReadWriteLock
  • StampedLock
  • 避免死锁的诀窍
  • 总结与对比

锁的作用

生活中的例子:公共厕所一次只能进一人,门上的“有人/无人”标志就是锁。
程序中的作用:当多个线程操作共享资源(如银行账户余额)时,锁保证数据安全。


synchronized 关键字

1. 同步方法

class BankAccount {
    private int balance = 100;

    // 锁住整个对象
    public synchronized void withdraw(int amount) {
        if (balance >= amount) {
            System.out.println(Thread.currentThread().getName() + " 取款 " + amount);
            balance -= amount;
        }
    }
}

类比:厕所门自动上锁,其他人必须等待。

2. 同步代码块

public void withdraw(int amount) {
    // 只锁关键代码
    synchronized(this) { 
        if (balance >= amount) {
            balance -= amount;
        }
    }
}

优势:缩小锁范围,提高效率。


ReentrantLock

import java.util.concurrent.locks.ReentrantLock;

class TicketSeller {
    private int tickets = 10;
    private ReentrantLock lock = new ReentrantLock();

    public void sellTicket() {
        lock.lock(); // 手动加锁
        try {
            if (tickets > 0) {
                System.out.println(Thread.currentThread().getName() + " 卖出第 " + tickets--);
            }
        } finally {
            lock.unlock(); // 必须手动释放!
        }
    }
}

特点

  • 支持公平锁(new ReentrantLock(true)
  • 可尝试获取锁(tryLock()
  • 可中断等待(lockInterruptibly()

类比:手动开关的防盗门,灵活控制进出规则。


ReadWriteLock

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class Cache {
    private Object data = null;
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    // 读操作:共享锁
    public Object getData() {
        rwLock.readLock().lock();
        try {
            return data;
        } finally {
            rwLock.readLock().unlock();
        }
    }

    // 写操作:独占锁
    public void updateData(Object newData) {
        rwLock.writeLock().lock();
        try {
            data = newData;
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}

适用场景:读多写少(如商品库存查询)。


StampedLock

import java.util.concurrent.locks.StampedLock;

class Point {
    private double x, y;
    private StampedLock lock = new StampedLock();

    // 乐观读:假设写操作很少发生
    public double distanceFromOrigin() {
        long stamp = lock.tryOptimisticRead();
        double currentX = x, currentY = y;
        if (!lock.validate(stamp)) { // 检查是否有写操作
            stamp = lock.readLock(); // 转为悲观读锁
            try {
                currentX = x;
                currentY = y;
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
}

特点:在读多写少时性能更高,但实现复杂。


避免死锁的诀窍

经典死锁场景:两人在独木桥相遇,互不相让。
解决方案

  1. 固定顺序获取锁:比如先锁 A 再锁 B。
  2. 设置超时时间tryLock(5, TimeUnit.SECONDS)

总结与对比

锁类型特点适用场景
synchronized自动加锁/释放,简单但性能较低简单同步需求
ReentrantLock手动控制,支持公平锁/条件变量复杂同步场景
ReadWriteLock读写分离,提升读性能读多写少(如缓存)
StampedLock乐观读,性能最高但实现复杂极高并发读,极少写

提示:实际开发中优先选择 synchronized,需要高级功能时再考虑其他锁。

相关文章:

  • delphi intraweb 警告框
  • bluecode-数字增殖问题
  • CPU 4核8个逻辑处理器
  • 微服务集成测试 -华为OD机试真题(A卷、JavaScript)
  • 洛谷题单2-P5717 【深基3.习8】三角形分类-python-流程图重构
  • 页面加载过多图片导致卡顿——解决方案详解
  • 【蓝桥杯】单片机设计与开发,速成备赛
  • idea打包Plugin ‘org.springframework.boot:spring-boot-maven-plugin:’ not found
  • 【奇点时刻】GPT-4o新生图特性深度洞察报告
  • QT之QML(简单示例)
  • Three.js 实现 3D 数学欧拉角
  • 第六天 - os/subprocess模块 - 系统进程管理 - 练习:服务状态监控脚本
  • Qt远程连接数据库,注册,登录
  • 2025年江苏省职业院校技能大赛 (高职组)大数据应用开发赛项任务书 (样题)
  • 大语言模型智体的综述:方法论、应用和挑战(下)
  • C#高级:利用LINQ进行实体列表的集合运算
  • 基于SpringBoot的网上订餐系统(源码+数据库+万字文档+开题报告+ppt)
  • 核心知识——Spark核心数据结构:RDD
  • Libevent TCP开发指南
  • Python Web 框架 django-vue3-admin快速入门 django后台管理
  • 人民日报评论员观察:稳就业,抓好存量、增量、质量
  • 旅马大熊猫“福娃”“凤仪”平安回国
  • 一女游客在稻城亚丁景区因高反去世,急救两个多小时未能恢复生命体征
  • 广东缉捕1名象牙走私潜逃非洲“红通”逃犯
  • 魔都眼|邮轮港国际帆船赛启动,120名中外选手展开角逐
  • 东部沿海大省浙江,为何盯上内河航运?