当前位置:首页 > 后端开发 > 正文

Java如何加监视器?

在Java中通过synchronized关键字实现监视器机制,对共享资源加锁确保线程安全,具体方式:,1. 同步代码块:synchronized(obj){…},2. 同步方法:public synchronized void method(){…},3. 配合wait()/notify()实现线程间通信

在Java中,监视器(Monitor)是一种同步机制,用于控制多线程环境下对共享资源的访问,它通过内置锁(synchronized)和线程通信方法(wait(), notify(), notifyAll())实现线程安全,以下是详细实现方法:


监视器的核心:synchronized 关键字

Java 中每个对象都有一个内置锁(Monitor Lock),通过 synchronized 关键字触发:

  1. 同步代码块
    锁定指定对象:

    Java如何加监视器?  第1张

    public void safeMethod() {
        synchronized (lockObject) { // lockObject 是任意对象
            // 临界区代码(共享资源操作)
        }
    }
  2. 同步方法
    锁定当前实例(this)或类(静态方法):

    public synchronized void safeMethod() { 
        // 操作共享资源 
    }
    public static synchronized void staticSafeMethod() { 
        // 静态方法锁定 Class 对象 
    }

线程通信:wait() 与 notify()

监视器通过 wait()notify() 实现线程间协作:

  1. wait()
    释放锁并让线程进入等待状态(需在 synchronized 块内调用):

    synchronized (lockObject) {
        while (条件不满足) {
            lockObject.wait(); // 释放锁,线程等待
        }
        // 条件满足后继续执行
    }
  2. notify() / notifyAll()
    唤醒等待线程(notify() 随机唤醒一个,notifyAll() 唤醒所有):

    synchronized (lockObject) {
        // 改变条件
        lockObject.notify(); // 唤醒一个等待线程
        // 或 lockObject.notifyAll();
    }

完整示例:生产者-消费者模型

import java.util.LinkedList;
import java.util.Queue;
public class MonitorExample {
    private final Queue<Integer> queue = new LinkedList<>();
    private final int CAPACITY = 5;
    private final Object lock = new Object(); // 监视器锁对象
    // 生产者
    public void produce(int item) throws InterruptedException {
        synchronized (lock) {
            while (queue.size() == CAPACITY) {
                lock.wait(); // 队列满时等待
            }
            queue.add(item);
            System.out.println("生产: " + item);
            lock.notifyAll(); // 唤醒消费者
        }
    }
    // 消费者
    public void consume() throws InterruptedException {
        synchronized (lock) {
            while (queue.isEmpty()) {
                lock.wait(); // 队列空时等待
            }
            int item = queue.poll();
            System.out.println("消费: " + item);
            lock.notifyAll(); // 唤醒生产者
        }
    }
}

关键注意事项

  1. 避免死锁
    • 确保锁的获取顺序一致。
    • 使用超时机制:wait(long timeout)
  2. 使用 while 而非 if 检查条件
    防止虚假唤醒(Spurious Wakeup),重复检查条件。
  3. 优先用 notifyAll()
    notify() 可能因唤醒错误线程导致死锁。
  4. 锁粒度优化
    减小同步代码块范围,提升性能(如避免在 synchronized 内执行耗时操作)。
  5. 替代方案
    复杂场景推荐 java.util.concurrent 包(如 ReentrantLockCondition)。

监视器的工作原理

  1. 当线程进入 synchronized 块时,获取对象的监视器锁。
  2. 若锁已被占用,线程进入阻塞队列(Entry Set) 等待。
  3. 线程调用 wait() 后,释放锁并进入等待队列(Wait Set)
  4. 其他线程调用 notify() 时,等待队列中的线程移至阻塞队列,重新竞争锁。

Java 的监视器机制通过 synchronized + wait()/notify() 实现线程同步与协作,正确使用时需注意:

  • 锁范围最小化以提升性能。
  • while 循环检查条件,避免虚假唤醒。
  • 高并发场景优先使用 java.util.concurrent 工具类(如 BlockingQueue)。

引用说明基于 Oracle 官方文档 Java Concurrency 和 Brian Goetz 所著《Java Concurrency in Practice》,实践代码遵循线程安全最佳实践,适用于 JDK 8 及以上版本。

0