Java教程——guava并发编程(2)

发布于:2025-07-12 ⋅ 阅读:(21) ⋅ 点赞:(0)

Java 并发编程深度解析:锁机制与 Guava Monitor

一、锁的本质与作用

1. 锁是什么?

锁是并发编程中的同步机制,用于控制多个线程对共享资源的访问。可以理解为资源访问的"许可证"机制 - 只有获得锁的线程才能访问共享资源。

2. 锁的核心作用

作用 说明 示例场景
互斥访问 确保同一时间只有一个线程访问共享资源 银行账户余额修改
可见性保证 确保一个线程的修改对其他线程可见 缓存数据更新
有序性控制 确保操作按预期顺序执行 数据库事务操作

3. 锁与并发/异步编程的关系

并发编程
共享资源访问
需要同步机制
锁机制
原子变量
并发集合
异步编程
非阻塞操作
Future/CompletableFuture
避免锁竞争
可能成为性能瓶颈
更高并发性
  • 并发编程:需要锁来解决共享资源竞争问题
  • 异步编程:通过非阻塞模型减少锁的使用,但底层资源访问仍可能需要锁
  • 最佳实践:在共享资源访问点使用锁,在非阻塞操作中使用异步机制

二、ReentrantLock 详解

1. ReentrantLock 核心特性

  • 可重入性:同一线程可多次获取同一把锁
  • 公平性选择:支持公平锁与非公平锁
  • 条件变量:可创建多个 Condition 对象
  • 锁中断:支持响应中断的锁获取
  • 尝试获取:提供 tryLock() 方法

2. 完整使用示例

import java.util.concurrent.locks.*;

public class ReentrantLockDemo {
   
    private final ReentrantLock lock = new ReentrantLock();
    private int counter = 0;
    
    public void increment() {
   
        lock.lock();  // 获取锁
        try {
   
            counter++;
            System.out.println(Thread.currentThread().getName() + 
                              " incremented to: " + counter);
        } finally {
   
            lock.unlock();  // 确保释放锁
        }
    }
    
    public void conditionalUpdate() throws InterruptedException {
   
        Condition condition = lock.newCondition();
        
        if (lock.tryLock(1, TimeUnit.SECONDS)) {
     // 尝试获取锁
            try {
   
                while (counter < 5) {
   
                    System.out.println("Waiting for condition...");
                    condition.await(500, TimeUnit.MILLISECONDS);  // 条件等待
                }
                counter = 0;
                System.out.println("Counter reset to 0");
                condition.signalAll();  // 通知所有等待线程
            } finally {
   
                lock.unlock();
            }
        } else {
   
            System.out.println("Could not acquire lock in time");
        }
    }

    public static void main(String[] args) {
   
        ReentrantLockDemo demo = new ReentrantLockDemo();
        
        // 创建多个线程并发访问
        for (int i = 0; i < 5; i++) {
   
            new Thread(() -> {
   
                for (int j = 0; j < 3; j++) {
   
                    demo.increment();
                }
            }).start();
        }
    }
}

3. 关键方法解析

方法 说明 使用场景
lock() 获取锁,阻塞直到成功 必须访问临界区时
tryLock() 尝试获取锁,立即返回结果 避免长时间阻塞
tryLock(timeout, unit) 带超时的锁获取 避免死锁
lockInterruptibly() 可中断的锁获取 需要响应中断的场景
newCondition() 创建条件变量 复杂条件等待场景

三、ReentrantLock vs synchronized

特性 ReentrantLock synchronized
实现机制 API 实现 JVM 内置关键字
锁获取方式 lock()/tryLock() 自动获取和释放
公平性 支持公平/非公平 非公平锁
条件变量 支持多个 Condition 单一 wait/notify
锁中断 支持 lockInterruptibly() 不支持
超时控制 支持 tryLock(timeout) 不支持
性能 高竞争下更优 低竞争下更优
代码灵活性 高(可跨方法) 低(代码块内)
异常处理 需手动释放锁 自动释放锁

四、Guava Monitor 深度解析

1. Monitor 是什么?

Monitor 是 Google Guava 库提供的高级锁工具,基于 ReentrantLock 构建,但提供更简洁的 API 和更安全的并发控制模式。

2. Monitor 核心优势

  1. 条件抽象:通过 Guard 对象封装条件逻辑
  2. 隐式信号:自动处理线程唤醒,避免信号丢失
  3. 可读性:代码更清晰表达业务意图
  4. 安全性:减少常见并发错误

3. Monitor 与 ReentrantLock/synchronized 的区别

特性 Monitor ReentrantLock synchronized
条件封装 Guard 对象 Condition 对象 无直接支持
信号处理 全自动 手动 signal/signalAll 手动 notify/notifyAll
多条件支持 多 Guard 支持 多 Condition 支持 单一条件
条件检查 自动循环检查 需手动 while 循环 需手动 while 循环
公平性 支持 支持 不支持
代码简洁性
学习曲线 较陡峭 中等 平缓

五、Guava Monitor 完整使用案例

1. 生产者-消费者模型实现

import com.google.common.util.concurrent.Monitor;
import java.util.ArrayList;
import java.util.List;

public class ProducerConsumerMonitor {
   
    private final Monitor monitor = new Monitor();
    private final List<Integer> buffer = new ArrayList<>();
    private static final int MAX_SIZE = 5;
    
    // 定义 Guard 条件
    private final Monitor.Guard notFull = new Monitor.Guard(monitor) {
   
        @Override
        public boolean isSatisfied() {
   
            return buffer.size() < MAX_SIZE; // 缓冲区未满
        }
    };
    
    private final Monitor.Guard notEmpty = new Monitor.Guard(monitor) {
   
        @Override
        public boolean isSatisfied() {
   
            return !buffer.isEmpty(); // 缓冲区非空
        }
    };
    
    public void produce(int item) throws InterruptedException {
   
        // 当缓冲区满时等待
        monitor.enterWhen(notFull);
        try {
   
            buffer.add(item);
            System.out.println("Produced: " + item + " | Buffer size: " + buffer.size());
        } finally {
   
            monitor.leave();
        }
    }
    
    public int consume() throws InterruptedException {
   
        // 当缓冲区空时等待
        monitor.enterWhen(notEmpty);
        try {
   
            int item = buffer.remove(0);
            System.out.println("Consumed: " + item + " | Buffer size: " + buffer.size());
            return item;
        } finally {
   
            monitor.leave();
        }
    }
    
    public static void main(String[] args) {
   
        ProducerConsumerMonitor pc = new ProducerConsumerMonitor();
        
        // 生产者线程
        Thread producer = new Thread(() -> {
   
            try {
   
                for (int i = 1; i <=

网站公告

今日签到

点亮在社区的每一天
去签到