Java 中各种锁的使用详解

Java 锁的使用详解

Java 提供了多种锁机制来处理并发编程中的同步问题。下面我将通过代码示例来展示各种锁的使用方法和特点。

锁的选择指南

以下是选择合适锁的指南:

基本锁类型演示

javascript 复制代码
// 由于这是在 Node.js 环境中模拟 Java 锁的概念,我们将使用注释和伪代码来解释

console.log("Java 锁的使用详解\n");

console.log("1. synchronized 关键字 (内置锁)");
console.log(`
public class SynchronizedExample {
    private int count = 0;
    
    // 同步方法 - 锁定当前对象实例
    public synchronized void increment() {
        count++;
    }
    
    // 同步代码块 - 锁定指定对象
    public void incrementBlock() {
        synchronized(this) {
            count++;
        }
    }
    
    // 静态同步方法 - 锁定类对象
    public static synchronized void staticMethod() {
        // 操作静态资源
    }
}
`);

console.log("\n2. ReentrantLock (可重入锁)");
console.log(`
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;
    
    public void increment() {
        // 获取锁
        lock.lock();
        try {
            count++;
        } finally {
            // 在 finally 块中释放锁,确保锁一定会被释放
            lock.unlock();
        }
    }
    
    // 尝试获取锁,带超时
    public void incrementWithTimeout() {
        try {
            // 尝试在 1 秒内获取锁
            boolean acquired = lock.tryLock(1, TimeUnit.SECONDS);
            if (acquired) {
                try {
                    count++;
                } finally {
                    lock.unlock();
                }
            } else {
                // 获取锁失败的处理
                System.out.println("无法获取锁");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}
`);

console.log("\n3. ReadWriteLock (读写锁)");
console.log(`
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private int data = 0;
    
    // 读操作 - 可以多个线程同时读
    public int readData() {
        rwLock.readLock().lock();
        try {
            return data;
        } finally {
            rwLock.readLock().unlock();
        }
    }
    
    // 写操作 - 只能一个线程写,且写时不能读
    public void writeData(int newValue) {
        rwLock.writeLock().lock();
        try {
            data = newValue;
        } finally {
            rwLock.writeLock().unlock();
        }
    }
}
`);

console.log("\n4. StampedLock (带版本号的锁)");
console.log(`
import java.util.concurrent.locks.StampedLock;

public class StampedLockExample {
    private final StampedLock lock = new StampedLock();
    private double x, y;
    
    // 写操作 - 独占模式
    public void move(double deltaX, double deltaY) {
        long stamp = lock.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            lock.unlockWrite(stamp);
        }
    }
    
    // 读操作 - 乐观读
    public double distanceFromOrigin() {
        // 乐观读,不阻塞写操作
        long stamp = lock.tryOptimisticRead();
        double currentX = x;
        double 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);
    }
    
    // 悲观读锁
    public double distanceFromOriginPessimistic() {
        long stamp = lock.readLock();
        try {
            return Math.sqrt(x * x + y * y);
        } finally {
            lock.unlockRead(stamp);
        }
    }
}
`);

console.log("\n5. Condition (条件变量)");
console.log(`
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    
    private final Object[] items = new Object[100];
    private int putIndex, takeIndex, count;
    
    // 生产者方法
    public void put(Object x) throws InterruptedException {
        lock.lock();
        try {
            // 缓冲区已满,等待
            while (count == items.length) {
                notFull.await();
            }
            
            items[putIndex] = x;
            putIndex = (putIndex + 1) % items.length;
            count++;
            
            // 通知消费者有新数据
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
    
    // 消费者方法
    public Object take() throws InterruptedException {
        lock.lock();
        try {
            // 缓冲区为空,等待
            while (count == 0) {
                notEmpty.await();
            }
            
            Object x = items[takeIndex];
            takeIndex = (takeIndex + 1) % items.length;
            count--;
            
            // 通知生产者有空间
            notFull.signal();
            return x;
        } finally {
            lock.unlock();
        }
    }
}
`);

console.log("\n6. Semaphore (信号量)");
console.log(`
import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    // 创建一个只允许5个线程同时访问的信号量
    private final Semaphore semaphore = new Semaphore(5);
    
    public void accessResource() {
        try {
            // 获取许可
            semaphore.acquire();
            
            try {
                // 访问资源
                System.out.println("访问资源中...");
                Thread.sleep(1000); // 模拟资源访问
            } finally {
                // 释放许可
                semaphore.release();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    // 尝试获取许可,不阻塞
    public void tryAccessResource() {
        boolean acquired = semaphore.tryAcquire();
        if (acquired) {
            try {
                // 访问资源
                System.out.println("访问资源中...");
            } finally {
                semaphore.release();
            }
        } else {
            System.out.println("无法获取许可,资源繁忙");
        }
    }
}
`);

console.log("\n7. CountDownLatch (倒计时门闩)");
console.log(`
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public void execute() throws InterruptedException {
        // 创建一个初始计数为3的CountDownLatch
        final CountDownLatch latch = new CountDownLatch(3);
        
        // 启动三个工作线程
        for (int i = 0; i < 3; i++) {
            final int taskId = i;
            new Thread(() -> {
                try {
                    // 模拟任务执行
                    System.out.println("任务 " + taskId + " 执行中...");
                    Thread.sleep(1000);
                    System.out.println("任务 " + taskId + " 完成");
                    
                    // 计数减一
                    latch.countDown();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }
        
        // 主线程等待所有工作线程完成
        System.out.println("等待所有任务完成...");
        latch.await();
        System.out.println("所有任务已完成,继续执行主线程");
    }
}
`);

console.log("\n8. CyclicBarrier (循环栅栏)");
console.log(`
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public void execute() {
        // 创建一个CyclicBarrier,当3个线程到达栅栏时,执行指定的任务
        final CyclicBarrier barrier = new CyclicBarrier(3, () -> {
            System.out.println("所有线程都到达栅栏,执行栅栏动作");
        });
        
        // 启动三个工作线程
        for (int i = 0; i < 3; i++) {
            final int taskId = i;
            new Thread(() -> {
                try {
                    System.out.println("线程 " + taskId + " 正在执行第一阶段");
                    Thread.sleep(1000);
                    
                    // 第一个栅栏点
                    System.out.println("线程 " + taskId + " 到达第一个栅栏");
                    barrier.await();
                    
                    System.out.println("线程 " + taskId + " 正在执行第二阶段");
                    Thread.sleep(1000);
                    
                    // 第二个栅栏点 (循环使用)
                    System.out.println("线程 " + taskId + " 到达第二个栅栏");
                    barrier.await();
                    
                    System.out.println("线程 " + taskId + " 完成所有工作");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}
`);

console.log("\n9. Phaser (阶段器)");
console.log(`
import java.util.concurrent.Phaser;

public class PhaserExample {
    public void execute() {
        // 创建一个初始参与者数量为1的Phaser (主线程)
        final Phaser phaser = new Phaser(1);
        
        // 创建并启动3个工作线程
        for (int i = 0; i < 3; i++) {
            final int taskId = i;
            // 注册一个参与者
            phaser.register();
            
            new Thread(() -> {
                try {
                    System.out.println("线程 " + taskId + " 开始第一阶段");
                    Thread.sleep(1000);
                    
                    // 到达第一阶段结束点,等待其他线程
                    System.out.println("线程 " + taskId + " 完成第一阶段");
                    phaser.arriveAndAwaitAdvance();
                    
                    System.out.println("线程 " + taskId + " 开始第二阶段");
                    Thread.sleep(1000);
                    
                    // 到达第二阶段结束点,等待其他线程
                    System.out.println("线程 " + taskId + " 完成第二阶段");
                    phaser.arriveAndAwaitAdvance();
                    
                    System.out.println("线程 " + taskId + " 开始第三阶段");
                    Thread.sleep(1000);
                    
                    // 完成所有阶段,取消注册
                    System.out.println("线程 " + taskId + " 完成所有阶段");
                    phaser.arriveAndDeregister();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }
        
        // 主线程等待所有工作线程完成第一阶段
        phaser.arriveAndAwaitAdvance();
        System.out.println("所有线程完成第一阶段");
        
        // 主线程等待所有工作线程完成第二阶段
        phaser.arriveAndAwaitAdvance();
        System.out.println("所有线程完成第二阶段");
        
        // 主线程等待所有工作线程完成第三阶段
        phaser.arriveAndAwaitAdvance();
        System.out.println("所有线程完成所有阶段");
        
        // 主线程取消注册
        phaser.arriveAndDeregister();
    }
}
`);

console.log("\n10. 锁的最佳实践");
console.log(`
1. 尽量缩小同步范围,只锁定必要的代码块
2. 避免在持有锁的情况下执行耗时操作
3. 避免死锁:
   - 按固定顺序获取多个锁
   - 使用带超时的锁获取方法
   - 使用 tryLock() 方法避免死锁
4. 优先使用并发集合而不是同步集合
5. 考虑使用无锁数据结构和原子变量
6. 适当选择锁类型:
   - 简单场景:synchronized
   - 需要高级特性:ReentrantLock
   - 读多写少:ReadWriteLock
   - 高并发读场景:StampedLock
`);

各种锁的特点比较

锁类型 可重入 公平性选择 阻塞 超时等待 可中断 适用场景
synchronized 简单同步场景
ReentrantLock 需要高级特性的场景
ReadWriteLock 读多写少场景
StampedLock 部分 高性能读多写少场景
Semaphore 资源数量控制
CountDownLatch 等待多个线程完成
CyclicBarrier 多个线程相互等待
Phaser 分阶段任务协调

希望这些示例和说明能帮助您理解Java中各种锁的使用方法和适用场景。

相关推荐
明月看潮生2 小时前
青少年编程与数学 02-019 Rust 编程基础 05课题、复合数据类型
开发语言·青少年编程·rust·编程与数学
心灵宝贝2 小时前
IDEA 安装 SpotBugs 插件超简单教程
java·macos·intellij-idea
幼稚诠释青春2 小时前
Java学习笔记(对象)
java·开发语言
小羊学伽瓦2 小时前
【Java基础】——JVM
java·jvm
老任与码2 小时前
Spring AI(2)—— 发送消息的API
java·人工智能·spring ai
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧3 小时前
MyBatis快速入门——实操
java·spring boot·spring·intellij-idea·mybatis·intellij idea
csdn_freak_dd3 小时前
查看单元测试覆盖率
java·单元测试
爱吃烤鸡翅的酸菜鱼3 小时前
【SpringMVC】详解cookie,session及实战
java·http·java-ee·intellij-idea
Wyc724093 小时前
JDBC:java与数据库连接,Maven,MyBatis
java·开发语言·数据库
强化学习与机器人控制仿真3 小时前
Newton GPU 机器人仿真器入门教程(零)— NVIDIA、DeepMind、Disney 联合推出
开发语言·人工智能·python·stm32·深度学习·机器人·自动驾驶