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中各种锁的使用方法和适用场景。

相关推荐
怒放吧德德4 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆6 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
心之语歌8 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊9 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang9 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang11 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解11 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SimonKing15 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean15 小时前
Jackson View Extension Spring Boot Starter
java·后端
Seven9716 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java