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

相关推荐
xyliiiiiL36 分钟前
从责任链模式聊到aware接口
java·开发语言
Elec_z2 小时前
网络深处的守门人
开发语言·网络
闪电麦坤953 小时前
C#:Time.deltaTime
开发语言·c#
码农老起4 小时前
与Aspose.pdf类似的jar库分享
java·pdf·jar
程序猿小D4 小时前
第三百八十九节 JavaFX教程 - JavaFX WebEngine
java·eclipse·intellij-idea·vr·javafx
Alfadi联盟 萧瑶5 小时前
Python-Django入手
开发语言·python·django
-代号95276 小时前
【JavaScript】十二、定时器
开发语言·javascript·ecmascript
勘察加熊人6 小时前
c++实现录音系统
开发语言·c++
self-discipline6346 小时前
【Java】Java核心知识点与相应面试技巧(七)——类与对象(二)
java·开发语言·面试
wei3872452326 小时前
java笔记02
java·开发语言·笔记