Java案例如何使用悲观锁?

wen java案例 17

本文目录导读:

Java案例如何使用悲观锁?

  1. Java中使用悲观锁的案例
  2. 性能对比与选择建议
  3. 使用建议

Java中使用悲观锁的案例

悲观锁的核心思想是:在访问共享资源前,先锁定资源,确保其他线程无法同时访问,以下是几种常见的实现方式:

synchronized 关键字(最基础)

public class PessimisticLockExample {
    private int count = 0;
    private final Object lock = new Object();
    // 方法级别的悲观锁
    public synchronized void increment() {
        count++;
    }
    // 代码块级别的悲观锁(更灵活)
    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }
}

ReentrantLock(可重入锁)

import java.util.concurrent.locks.ReentrantLock;
public class BankAccount {
    private double balance;
    private final ReentrantLock lock = new ReentrantLock();
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }
    // 转账方法 - 使用悲观锁
    public void transfer(double amount) {
        lock.lock();  // 获取锁
        try {
            if (balance >= amount) {
                System.out.println(Thread.currentThread().getName() + " 开始转账: " + amount);
                Thread.sleep(100);  // 模拟耗时操作
                balance -= amount;
                System.out.println(Thread.currentThread().getName() + " 转账成功,余额: " + balance);
            } else {
                System.out.println("余额不足,当前余额: " + balance);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();  // 释放锁
        }
    }
    public static void main(String[] args) {
        BankAccount account = new BankAccount(1000);
        // 模拟多个用户同时转账
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                account.transfer(200);
            }).start();
        }
    }
}

数据库层面的悲观锁(Java + MySQL)

import java.sql.*;
public class DatabasePessimisticLock {
    // 使用 SELECT ... FOR UPDATE 加悲观锁
    public void updateWitnPessimisticLock(int productId, int quantity) {
        String selectSql = "SELECT quantity FROM products WHERE id = ? FOR UPDATE";
        String updateSql = "UPDATE products SET quantity = ? WHERE id = ?";
        try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
             PreparedStatement selectStmt = conn.prepareStatement(selectSql);
             PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
            // 开启事务
            conn.setAutoCommit(false);
            // 查询并加锁
            selectStmt.setInt(1, productId);
            ResultSet rs = selectStmt.executeQuery();
            if (rs.next()) {
                int currentQuantity = rs.getInt("quantity");
                if (currentQuantity >= quantity) {
                    // 更新库存
                    updateStmt.setInt(1, currentQuantity - quantity);
                    updateStmt.setInt(2, productId);
                    updateStmt.executeUpdate();
                    conn.commit();
                    System.out.println("库存更新成功");
                } else {
                    conn.rollback();
                    System.out.println("库存不足");
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

实际应用场景:库存扣减系统

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicInteger;
public class InventorySystem {
    private AtomicInteger stock = new AtomicInteger(100);
    private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
    // 使用悲观锁确保库存操作原子性
    public boolean deductStock(int quantity) {
        lock.lock();
        try {
            // 模拟业务处理时间
            Thread.sleep(50);
            int currentStock = stock.get();
            if (currentStock >= quantity) {
                // 扣减库存
                stock.addAndGet(-quantity);
                System.out.println(Thread.currentThread().getName() + 
                    " 扣减成功,当前库存: " + stock.get());
                return true;
            } else {
                System.out.println(Thread.currentThread().getName() + 
                    " 库存不足,当前库存: " + currentStock + ",需要: " + quantity);
                return false;
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        InventorySystem system = new InventorySystem();
        // 模拟并发购买
        for (int i = 0; i < 10; i++) {
            final int quantity = 10;
            new Thread(() -> {
                system.deductStock(quantity);
            }, "用户-" + i).start();
        }
    }
}

性能对比与选择建议

特性 synchronized ReentrantLock 数据库锁
使用简便性 ✅ 简单 ⚠️ 较复杂 ❌ 复杂
性能 ❌ 较差 ✅ 较好 ⚠️ 一般
灵活性 ❌ 低 ✅ 高 ✅ 高
超时机制 ❌ 不支持 ✅ 支持 ✅ 支持
公平性 ❌ 非公平 ✅ 可选择 ⚠️ 取决于DB

使用建议

  1. 小规模并发:使用 synchronized 即可
  2. 高性能需求:使用 ReentrantLock
  3. 分布式系统:使用数据库锁或分布式锁(如 Redis、Zookeeper)
  4. 锁的范围要小:尽量缩小加锁的代码块
  5. 避免死锁:注意锁的获取顺序,使用 tryLock 避免无限等待

在实际项目中,优先使用无锁或乐观锁(如 AtomicInteger、CAS),只有在冲突概率较高时才考虑悲观锁。

抱歉,评论功能暂时关闭!