如何在Java中添加行锁?

在Java中,行锁通常通过synchronized关键字或ReentrantLock实现,synchronized修饰方法或代码块,确保同一时刻仅一个线程执行;ReentrantLock需手动lock()/unlock(),提供更灵活的锁控制。

在Java中实现”行锁”通常有两种场景:代码层面的对象锁(模拟行锁行为)和数据库行锁,下面从技术原理、实现方式和最佳实践进行详细说明,确保内容符合专业性与可靠性标准。

如何在Java中添加行锁?


代码层面的对象锁(模拟行锁)

当需要锁定单个对象实例(类比数据库中的一行数据)时,可通过以下方式实现:

synchronized 关键字

public class Account {
    private final Object lock = new Object(); // 专用锁对象
    private int balance;
    public void transfer(Account target, int amount) {
        // 锁定当前对象(模拟行锁)
        synchronized (this) {
            // 锁定目标对象
            synchronized (target) {
                this.balance -= amount;
                target.balance += amount;
            }
        }
    }
}

原理

  • 每个对象内置一个监视器锁(Monitor),synchronized 基于此实现互斥。
  • 锁定 this 或自定义锁对象,相当于对”行”(对象实例)加锁。

注意事项

  • 避免嵌套锁导致的死锁(如上例需按固定顺序加锁)。
  • 锁范围应尽量缩小(仅在临界区加锁)。

ReentrantLock 显式锁

import java.util.concurrent.locks.ReentrantLock;
public class RowLockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int data;
    public void updateData(int value) {
        lock.lock(); // 加锁
        try {
            data = value; // 临界区操作
        } finally {
            lock.unlock(); // 必须释放锁
        }
    }
}

优势

如何在Java中添加行锁?

  • 支持公平锁、超时尝试(tryLock)、可中断等待。
  • 更灵活的锁控制。

数据库行锁(Java中操作)

当锁的目标是数据库中的行记录时,需通过SQL实现:

悲观锁(SELECT FOR UPDATE

// JDBC 示例(以MySQL为例)
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
conn.setAutoCommit(false);
try {
    // 锁定id=100的行
    PreparedStatement stmt = conn.prepareStatement(
        "SELECT * FROM accounts WHERE id = ? FOR UPDATE"
    );
    stmt.setInt(1, 100);
    ResultSet rs = stmt.executeQuery();
    // 更新操作
    PreparedStatement updateStmt = conn.prepareStatement(
        "UPDATE accounts SET balance = balance - 100 WHERE id = ?"
    );
    updateStmt.setInt(1, 100);
    updateStmt.executeUpdate();
    conn.commit(); // 提交事务释放锁
} catch (SQLException e) {
    conn.rollback();
}

关键点

  • FOR UPDATE 在事务中锁定查询到的行。
  • 事务提交/回滚后自动释放锁。
  • 需配合事务隔离级别(推荐 READ_COMMITTEDREPEATABLE_READ)。

乐观锁(版本控制)

// 更新时检查版本号
UPDATE products 
SET stock = stock - 1, version = version + 1 
WHERE id = 123 AND version = 5;

原理

  • 读取数据时记录版本号(或时间戳)。
  • 更新时校验版本号,失败则重试或抛异常。
  • 适合低冲突场景,避免长期锁竞争。

如何选择锁方案?

场景 推荐方案
单JVM内的对象互斥 synchronizedReentrantLock
高并发数据库写操作 悲观锁(FOR UPDATE
读多写少、冲突概率低 乐观锁(版本控制)

避坑指南

  1. 死锁预防

    如何在Java中添加行锁?

    • 代码锁:按固定顺序获取锁(如按对象ID排序)。
    • 数据库锁:设置锁超时(innodb_lock_wait_timeout)。
  2. 性能优化

    • 缩小锁范围(减少临界区代码)。
    • 无锁化设计(如 ConcurrentHashMap)。
  3. 分布式环境

    • 使用分布式锁(Redis Redlock、ZooKeeper)。
    • 避免数据库行锁跨服务失效。

  • 代码级”行锁”:通过 synchronizedReentrantLock 锁定对象实例。
  • 数据库行锁:依赖SQL的 FOR UPDATE 或乐观锁实现。
  • 核心原则:最小化锁范围、预防死锁、匹配业务场景。

引用说明

原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/21362.html

(0)
酷盾叔的头像酷盾叔
上一篇 2025年6月12日 17:42
下一篇 2025年6月12日 17:48

相关推荐

  • Java如何高效实现审核状态功能?

    在Java中可通过枚举定义审核状态(如待审核、通过、拒绝),结合数据库状态字段存储数值标识,利用状态模式处理状态转换逻辑,通过条件判断或策略类实现不同状态下的业务操作,确保流程清晰易维护。

    2025年5月28日
    300
  • Java如何高效存储数据?

    在Java中可通过变量存储基本数据,集合框架(如List/Map)管理对象组,数组存放同类型元素,文件/数据库持久化数据,或利用对象封装属性实现结构化存储。

    2025年6月2日
    300
  • Java应用开发入门指南

    使用Java编写应用小程序需安装JDK与IDE(如Eclipse),创建项目后编写Java类,实现核心逻辑,编译为字节码,通过main方法或框架启动运行,可开发桌面、Web后端或安卓应用,遵循面向对象原则确保可扩展性。

    2025年6月1日
    400
  • Java二进制计算原理详解

    Java中二进制基于0和1表示数值,支持字面值(如0b101)、位运算(&,|,~,

    2025年6月9日
    200
  • 如何在Java中实现用户注册?

    Java注册实现需创建用户实体类,设计数据库表(如用户ID、账号、密码字段),编写DAO层接口进行数据库操作(如insert用户信息),并在Service层处理业务逻辑(如密码加密、重复账号校验),Controller层接收前端表单数据(如POST请求),调用Service完成注册,返回结果(成功跳转/失败提示)。

    2025年6月9日
    100

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN