wait notify案例

wen java案例 3

本文目录导读:

wait notify案例

  1. 经典生产者-消费者案例
  2. 改进版本(支持多个生产者消费者)
  3. 更实用的阻塞队列实现案例
  4. 关键要点和注意事项
  5. 生产环境建议

我来为你提供一个完整的 wait/notify 生产者-消费者案例,并详细解释其工作原理。

经典生产者-消费者案例

import java.util.LinkedList;
import java.util.Queue;
/**
 * 使用 wait/notify 实现生产者-消费者模式
 */
public class ProducerConsumerExample {
    // 共享缓冲区
    private final Queue<Integer> buffer = new LinkedList<>();
    private final int MAX_SIZE = 5;  // 缓冲区最大容量
    /**
     * 生产者:往缓冲区添加数据
     */
    public synchronized void produce() throws InterruptedException {
        // 当缓冲区已满时,生产者等待
        while (buffer.size() == MAX_SIZE) {
            System.out.println("【生产者】缓冲区已满,等待消费者消费...");
            wait();  // 释放锁并等待
        }
        // 生产数据
        int data = (int) (Math.random() * 100);
        buffer.offer(data);
        System.out.println("【生产者】生产数据: " + data + ",当前缓冲区大小: " + buffer.size());
        // 通知消费者可以消费了
        notifyAll();
        // 模拟生产过程耗时
        Thread.sleep(500);
    }
    /**
     * 消费者:从缓冲区取出数据
     */
    public synchronized void consume() throws InterruptedException {
        // 当缓冲区为空时,消费者等待
        while (buffer.isEmpty()) {
            System.out.println("【消费者】缓冲区为空,等待生产者生产...");
            wait();  // 释放锁并等待
        }
        // 消费数据
        int data = buffer.poll();
        System.out.println("【消费者】消费数据: " + data + ",当前缓冲区大小: " + buffer.size());
        // 通知生产者可以继续生产了
        notifyAll();
        // 模拟消费过程耗时
        Thread.sleep(500);
    }
    /**
     * 测试主方法
     */
    public static void main(String[] args) {
        ProducerConsumerExample example = new ProducerConsumerExample();
        // 创建生产者线程
        Thread producerThread = new Thread(() -> {
            try {
                while (true) {
                    example.produce();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "生产者线程");
        // 创建消费者线程
        Thread consumerThread = new Thread(() -> {
            try {
                while (true) {
                    example.consume();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "消费者线程");
        // 启动线程
        producerThread.start();
        consumerThread.start();
    }
}

改进版本(支持多个生产者消费者)

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * 多生产者-多消费者案例
 */
public class MultiProducerConsumer {
    private final Queue<Integer> buffer = new LinkedList<>();
    private final int MAX_SIZE = 3;
    private final AtomicInteger counter = new AtomicInteger(0);
    // 锁对象
    private final Object lock = new Object();
    /**
     * 生产者方法
     */
    public void produce(String producerName) throws InterruptedException {
        synchronized (lock) {
            // 使用 while 循环检查条件(防止虚假唤醒)
            while (buffer.size() >= MAX_SIZE) {
                System.out.println(producerName + ": 缓冲区已满,等待...");
                lock.wait();  // 释放 lock 锁
            }
            int data = counter.incrementAndGet();
            buffer.offer(data);
            System.out.println(producerName + ": 生产了 " + data + ",当前大小: " + buffer.size());
            // 通知所有等待的线程
            lock.notifyAll();
            Thread.sleep(300);
        }
    }
    /**
     * 消费者方法
     */
    public void consume(String consumerName) throws InterruptedException {
        synchronized (lock) {
            // 使用 while 循环检查条件(防止虚假唤醒)
            while (buffer.isEmpty()) {
                System.out.println(consumerName + ": 缓冲区为空,等待...");
                lock.wait();  // 释放 lock 锁
            }
            int data = buffer.poll();
            System.out.println(consumerName + ": 消费了 " + data + ",当前大小: " + buffer.size());
            // 通知所有等待的线程
            lock.notifyAll();
            Thread.sleep(300);
        }
    }
    public static void main(String[] args) {
        MultiProducerConsumer example = new MultiProducerConsumer();
        // 创建多个生产者
        for (int i = 1; i <= 2; i++) {
            final String producerName = "生产者" + i;
            new Thread(() -> {
                try {
                    while (true) {
                        example.produce(producerName);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }
        // 创建多个消费者
        for (int i = 1; i <= 2; i++) {
            final String consumerName = "消费者" + i;
            new Thread(() -> {
                try {
                    while (true) {
                        example.consume(consumerName);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
        }
    }
}

更实用的阻塞队列实现案例

import java.util.LinkedList;
import java.util.Queue;
/**
 * 自定义阻塞队列(类似 BlockingQueue 的简单实现)
 */
public class CustomBlockingQueue<T> {
    private final Queue<T> queue;
    private final int capacity;
    private final Object lock = new Object();
    public CustomBlockingQueue(int capacity) {
        this.queue = new LinkedList<>();
        this.capacity = capacity;
    }
    /**
     * 添加元素(如果队列满了,则阻塞)
     */
    public void put(T item) throws InterruptedException {
        synchronized (lock) {
            while (queue.size() >= capacity) {
                System.out.println("队列已满," + Thread.currentThread().getName() + " 等待...");
                lock.wait();
            }
            queue.offer(item);
            System.out.println(Thread.currentThread().getName() + " 添加: " + item 
                + ",队列大小: " + queue.size());
            lock.notifyAll();
        }
    }
    /**
     * 取出元素(如果队列空了,则阻塞)
     */
    public T take() throws InterruptedException {
        synchronized (lock) {
            while (queue.isEmpty()) {
                System.out.println("队列为空," + Thread.currentThread().getName() + " 等待...");
                lock.wait();
            }
            T item = queue.poll();
            System.out.println(Thread.currentThread().getName() + " 取出: " + item 
                + ",队列大小: " + queue.size());
            lock.notifyAll();
            return item;
        }
    }
    /**
     * 测试
     */
    public static void main(String[] args) {
        CustomBlockingQueue<Integer> queue = new CustomBlockingQueue<>(3);
        // 生产者
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    queue.put(i);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "生产者").start();
        // 消费者
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    queue.take();
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "消费者").start();
    }
}

关键要点和注意事项

wait/notify 必须配合 synchronized 使用

// 正确写法
synchronized (lock) {
    while (condition) {
        lock.wait();
    }
    lock.notifyAll();
}

使用 while 而不是 if 检查条件

// ❌ 错误:使用 if 可能产生虚假唤醒问题
if (condition) {
    wait();
}
// ✅ 正确:使用 while 防止虚假唤醒
while (condition) {
    wait();
}

wait 释放锁的机制

  • wait() 释放对象锁并让出 CPU
  • notify() 随机唤醒一个等待线程(不释放锁)
  • notifyAll() 唤醒所有等待线程(不释放锁)

常用方法说明

方法 作用 锁的处理
wait() 让当前线程等待 释放锁
wait(long timeout) 等待指定时间 释放锁
notify() 唤醒一个等待线程 不释放锁
notifyAll() 唤醒所有等待线程 不释放锁

两个线程死锁的简单示例

public class DeadlockExample {
    public static void main(String[] args) {
        Object lock1 = new Object();
        Object lock2 = new Object();
        // 线程1
        new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread1: 持有 lock1");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                synchronized (lock2) {
                    System.out.println("Thread1: 持有 lock1 和 lock2");
                }
            }
        }).start();
        // 线程2(与线程1顺序相反,容易造成死锁)
        new Thread(() -> {
            synchronized (lock2) {
                System.out.println("Thread2: 持有 lock2");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                synchronized (lock1) {
                    System.out.println("Thread2: 持有 lock1 和 lock2");
                }
            }
        }).start();
    }
}

生产环境建议

在实际生产环境中,推荐使用 java.util.concurrent 包提供的工具类:

// 使用阻塞队列
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);
// 生产者
new Thread(() -> {
    try {
        queue.put(data);  // 自动阻塞
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();
// 消费者
new Thread(() -> {
    try {
        int data = queue.take();  // 自动阻塞
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}).start();

这些标准库组件已经处理好了线程安全、性能优化等问题,可以减少手动编写 wait/notify 代码。

抱歉,评论功能暂时关闭!