当前位置: 首页 > article >正文

Java 中各种锁的使用详解

Java 锁的使用详解

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

锁的选择指南

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

在这里插入图片描述

基本锁类型演示

// 由于这是在 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中各种锁的使用方法和适用场景。


http://www.kler.cn/a/613032.html

相关文章:

  • Node.js 如何发布一个 NPM 包——详细教程
  • 第R9周:阿尔兹海默症诊断(优化特征选择版)
  • 美摄科技智能汽车车内实时AR特效方案,让出行充满乐趣
  • 神经网络知识
  • 【极速版 -- 大模型入门到进阶】LORA:大模型轻量级微调
  • 智能网联交通加速落地,光路科技TSN技术助推车路云一体化发展
  • 跟着尚硅谷学vue-day1
  • LeetCode 1492 n的第K个因子
  • 浅谈工商企业用电管理的分布式储能设计
  • window系统下安装elk
  • unity一个图片的物体,会有透明的效果
  • 【机器学习】从回声定位到优化引擎:蝙蝠算法在SVR超参数优化中的应用
  • Golang 的 GMP 调度机制常见问题及解答
  • Mininet--log.py-全局函数作用
  • Box86源码剖析(三)
  • JSP笔记
  • python多态、静态方法和类方法
  • 高速电路中的存储器应用与设计三
  • Vala 编程语言教程-继承
  • C 语言文件读写操作详解