Java并发编程初级系列第8篇 wait()和sleep()都可以让线程暂停执行,但它们的工作原理和使用场景完全不同。这是Java并发编程中新手最容易混淆的概念之一。本文将详细解释它们的区别和正确用法。

🤔 初学者的困惑

看似相似的功能

public class ConfusionExample {
    
    /**
     * 新手常见的困惑
     */
    public static void demonstrateConfusion() {
        System.out.println("=== 新手常见困惑 ===");
        
        // 都可以让线程暂停
        System.out.println("Thread.sleep(1000) - 让线程睡眠1秒");
        System.out.println("object.wait(1000) - 让线程等待1秒");
        
        System.out.println("\n看起来功能相似,但实际上完全不同!");
        
        // 错误的理解
        System.out.println("\n❌ 错误理解:");
        System.out.println("- 都是让线程暂停执行");
        System.out.println("- 可以互相替换使用");
        System.out.println("- 效果基本相同");
        
        // 正确的理解
        System.out.println("\n✅ 正确理解:");
        System.out.println("- sleep()是Thread类的静态方法");
        System.out.println("- wait()是Object类的实例方法");
        System.out.println("- 它们的使用场景和机制完全不同");
        System.out.println("- 对锁的处理方式不同");
        System.out.println("- 唤醒方式不同");
    }
    
    public static void main(String[] args) {
        demonstrateConfusion();
    }
}

😴 sleep()详解

sleep()的工作原理

public class SleepDetails {
    
    /**
     * sleep()基本用法演示
     */
    public static void demonstrateSleepBasics() throws InterruptedException {
        System.out.println("=== sleep()基本用法 ===");
        
        System.out.println("开始时间: " + new Date());
        
        // Thread.sleep()让当前线程暂停执行
        System.out.println("线程开始睡眠2秒...");
        Thread.sleep(2000);
        
        System.out.println("线程醒来了!");
        System.out.println("结束时间: " + new Date());
    }
    
    /**
     * sleep()不会释放锁
     */
    public static void demonstrateSleepWithLock() throws InterruptedException {
        System.out.println("\n=== sleep()不会释放锁 ===");
        
        Object lock = new Object();
        
        // 线程1:持有锁并睡眠
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("线程1:获得锁,开始睡眠...");
                try {
                    Thread.sleep(3000); // 睡眠时不释放锁
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("线程1:睡眠结束,释放锁");
            }
        }, "Thread-1");
        
        // 线程2:尝试获取同一个锁
        Thread thread2 = new Thread(() -> {
            System.out.println("线程2:尝试获取锁...");
            synchronized (lock) {
                System.out.println("线程2:获得锁!");
            }
        }, "Thread-2");
        
        thread1.start();
        Thread.sleep(100); // 确保线程1先启动
        thread2.start();
        
        thread1.join();
        thread2.join();
        
        System.out.println("观察:线程2必须等待线程1睡眠结束才能获得锁");
    }
    
    /**
     * sleep()可以被中断
     */
    public static void demonstrateSleepInterruption() throws InterruptedException {
        System.out.println("\n=== sleep()可以被中断 ===");
        
        Thread sleepingThread = new Thread(() -> {
            try {
                System.out.println("开始长时间睡眠...");
                Thread.sleep(10000); // 睡眠10秒
                System.out.println("睡眠正常结束");
            } catch (InterruptedException e) {
                System.out.println("睡眠被中断!");
                Thread.currentThread().interrupt(); // 恢复中断状态
            }
        }, "SleepingThread");
        
        sleepingThread.start();
        
        // 2秒后中断睡眠
        Thread.sleep(2000);
        System.out.println("中断睡眠线程...");
        sleepingThread.interrupt();
        
        sleepingThread.join();
    }
    
    /**
     * sleep()的不同重载方法
     */
    public static void demonstrateSleepOverloads() throws InterruptedException {
        System.out.println("\n=== sleep()的重载方法 ===");
        
        // 毫秒级睡眠
        System.out.println("毫秒级睡眠开始");
        Thread.sleep(1000); // 1秒
        System.out.println("毫秒级睡眠结束");
        
        // 纳秒级睡眠(实际精度取决于系统)
        System.out.println("纳秒级睡眠开始");
        Thread.sleep(0, 500000); // 0毫秒 + 500000纳秒 = 0.5毫秒
        System.out.println("纳秒级睡眠结束");
        
        System.out.println("注意:纳秒级精度在大多数系统上并不准确");
    }
    
    public static void main(String[] args) throws InterruptedException {
        demonstrateSleepBasics();
        demonstrateSleepWithLock();
        demonstrateSleepInterruption();
        demonstrateSleepOverloads();
    }
}

⏰ wait()详解

wait()的工作原理

public class WaitDetails {
    
    /**
     * wait()基本用法演示
     */
    public static void demonstrateWaitBasics() throws InterruptedException {
        System.out.println("=== wait()基本用法 ===");
        
        Object lock = new Object();
        
        // 等待线程
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("等待线程:开始等待...");
                    lock.wait(); // 释放锁并等待
                    System.out.println("等待线程:被唤醒了!");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "WaitingThread");
        
        // 唤醒线程
        Thread notifyingThread = new Thread(() -> {
            try {
                Thread.sleep(2000); // 等待2秒
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
            
            synchronized (lock) {
                System.out.println("唤醒线程:发送通知...");
                lock.notify(); // 唤醒等待的线程
            }
        }, "NotifyingThread");
        
        waitingThread.start();
        notifyingThread.start();
        
        waitingThread.join();
        notifyingThread.join();
    }
    
    /**
     * wait()会释放锁
     */
    public static void demonstrateWaitReleasesLock() throws InterruptedException {
        System.out.println("\n=== wait()会释放锁 ===");
        
        Object lock = new Object();
        
        // 线程1:获取锁并等待
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("线程1:获得锁,开始等待...");
                    lock.wait(); // 释放锁并等待
                    System.out.println("线程1:被唤醒,重新获得锁");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "Thread-1");
        
        // 线程2:获取同一个锁
        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1000); // 确保线程1先等待
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
            
            synchronized (lock) {
                System.out.println("线程2:获得锁(线程1在等待中)");
                try {
                    Thread.sleep(2000); // 持有锁2秒
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("线程2:唤醒线程1");
                lock.notify();
                System.out.println("线程2:释放锁");
            }
        }, "Thread-2");
        
        thread1.start();
        thread2.start();
        
        thread1.join();
        thread2.join();
        
        System.out.println("观察:线程2能够获得锁,说明wait()释放了锁");
    }
    
    /**
     * wait()必须在synchronized块中使用
     */
    public static void demonstrateWaitRequiresSynchronized() {
        System.out.println("\n=== wait()必须在synchronized块中使用 ===");
        
        Object lock = new Object();
        
        try {
            // 错误:在synchronized块外调用wait()
            lock.wait();
        } catch (IllegalMonitorStateException e) {
            System.out.println("错误:" + e.getClass().getSimpleName() + " - " + e.getMessage());
            System.out.println("wait()必须在synchronized块中调用");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // 正确用法
        synchronized (lock) {
            try {
                System.out.println("正确:在synchronized块中调用wait()");
                // lock.wait(); // 这里不实际调用,避免无限等待
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * wait()的不同重载方法
     */
    public static void demonstrateWaitOverloads() throws InterruptedException {
        System.out.println("\n=== wait()的重载方法 ===");
        
        Object lock = new Object();
        
        Thread timeoutWaitThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("开始带超时的等待(2秒)...");
                    lock.wait(2000); // 最多等待2秒
                    System.out.println("等待结束(可能是超时或被唤醒)");
                } catch (InterruptedException e) {
                    System.out.println("等待被中断");
                    Thread.currentThread().interrupt();
                }
            }
        }, "TimeoutWaitThread");
        
        timeoutWaitThread.start();
        timeoutWaitThread.join();
        
        // 演示精确时间的wait
        Thread preciseWaitThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("开始精确时间等待...");
                    lock.wait(1000, 500000); // 1秒 + 500000纳秒
                    System.out.println("精确时间等待结束");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "PreciseWaitThread");
        
        preciseWaitThread.start();
        preciseWaitThread.join();
    }
    
    public static void main(String[] args) throws InterruptedException {
        demonstrateWaitBasics();
        demonstrateWaitReleasesLock();
        demonstrateWaitRequiresSynchronized();
        demonstrateWaitOverloads();
    }
}

🆚 详细对比

核心差异对比

public class WaitVsSleepComparison {
    
    /**
     * 对比表格展示
     */
    public static void showComparisonTable() {
        System.out.println("=== wait() vs sleep() 详细对比 ===");
        System.out.println();
        
        System.out.printf("%-20s %-30s %-30s%n", "特性", "sleep()", "wait()");
        System.out.println("─".repeat(80));
        
        System.out.printf("%-20s %-30s %-30s%n", "所属类", "Thread类的静态方法", "Object类的实例方法");
        System.out.printf("%-20s %-30s %-30s%n", "锁的处理", "不释放锁", "释放锁");
        System.out.printf("%-20s %-30s %-30s%n", "使用位置", "任何地方", "必须在synchronized块中");
        System.out.printf("%-20s %-30s %-30s%n", "唤醒方式", "时间到或被中断", "notify/notifyAll或超时");
        System.out.printf("%-20s %-30s %-30s%n", "主要用途", "暂停执行", "线程间通信");
        System.out.printf("%-20s %-30s %-30s%n", "异常", "InterruptedException", "InterruptedException");
        System.out.printf("%-20s %-30s %-30s%n", "参数", "时间(毫秒/纳秒)", "时间(毫秒/纳秒)或无参");
        System.out.printf("%-20s %-30s %-30s%n", "典型场景", "延迟执行", "生产者消费者模式");
    }
    
    /**
     * 锁处理差异的实际演示
     */
    public static void demonstrateLockDifference() throws InterruptedException {
        System.out.println("\n=== 锁处理差异演示 ===");
        
        Object lock = new Object();
        
        // 测试sleep()不释放锁
        System.out.println("--- sleep()不释放锁 ---");
        
        Thread sleepThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Sleep线程:获得锁,开始睡眠1秒");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                System.out.println("Sleep线程:睡眠结束,释放锁");
            }
        }, "SleepThread");
        
        Thread competingThread1 = new Thread(() -> {
            System.out.println("竞争线程1:尝试获取锁...");
            synchronized (lock) {
                System.out.println("竞争线程1:获得锁!");
            }
        }, "CompetingThread1");
        
        sleepThread.start();
        Thread.sleep(100); // 确保sleepThread先获得锁
        competingThread1.start();
        
        sleepThread.join();
        competingThread1.join();
        
        System.out.println();
        
        // 测试wait()释放锁
        System.out.println("--- wait()释放锁 ---");
        
        Thread waitThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Wait线程:获得锁,开始等待");
                    lock.wait(1000); // 等待1秒或被唤醒
                    System.out.println("Wait线程:等待结束");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "WaitThread");
        
        Thread competingThread2 = new Thread(() -> {
            try {
                Thread.sleep(200); // 确保waitThread先等待
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
            
            System.out.println("竞争线程2:尝试获取锁...");
            synchronized (lock) {
                System.out.println("竞争线程2:获得锁!(wait线程正在等待)");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "CompetingThread2");
        
        waitThread.start();
        competingThread2.start();
        
        waitThread.join();
        competingThread2.join();
    }
    
    /**
     * 使用场景对比
     */
    public static void demonstrateUsageScenarios() throws InterruptedException {
        System.out.println("\n=== 使用场景对比 ===");
        
        // sleep()的典型使用场景
        System.out.println("--- sleep()典型场景:延迟执行 ---");
        
        System.out.println("执行任务1");
        Thread.sleep(1000); // 延迟1秒
        System.out.println("执行任务2");
        
        // wait()的典型使用场景:生产者消费者
        System.out.println("\n--- wait()典型场景:生产者消费者 ---");
        
        ProducerConsumerExample example = new ProducerConsumerExample();
        
        Thread producer = new Thread(example::produce, "Producer");
        Thread consumer = new Thread(example::consume, "Consumer");
        
        producer.start();
        consumer.start();
        
        Thread.sleep(3000); // 运行3秒
        
        example.stop();
        
        producer.join();
        consumer.join();
    }
    
    /**
     * 简单的生产者消费者示例
     */
    static class ProducerConsumerExample {
        private final Object lock = new Object();
        private int item = 0;
        private boolean hasItem = false;
        private volatile boolean running = true;
        
        public void produce() {
            while (running) {
                synchronized (lock) {
                    while (hasItem && running) {
                        try {
                            System.out.println("生产者:等待消费者消费");
                            lock.wait(); // 等待消费者消费
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    
                    if (running) {
                        item++;
                        hasItem = true;
                        System.out.println("生产者:生产了物品 " + item);
                        lock.notify(); // 通知消费者
                    }
                }
                
                try {
                    Thread.sleep(500); // 生产间隔
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
        
        public void consume() {
            while (running) {
                synchronized (lock) {
                    while (!hasItem && running) {
                        try {
                            System.out.println("消费者:等待生产者生产");
                            lock.wait(); // 等待生产者生产
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    
                    if (running && hasItem) {
                        System.out.println("消费者:消费了物品 " + item);
                        hasItem = false;
                        lock.notify(); // 通知生产者
                    }
                }
                
                try {
                    Thread.sleep(800); // 消费间隔
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
        
        public void stop() {
            running = false;
            synchronized (lock) {
                lock.notifyAll(); // 唤醒所有等待的线程
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        showComparisonTable();
        demonstrateLockDifference();
        demonstrateUsageScenarios();
    }
}

🔄 notify()和notifyAll()

唤醒机制详解

public class NotifyMechanism {
    
    /**
     * notify() vs notifyAll() 的区别
     */
    public static void demonstrateNotifyDifference() throws InterruptedException {
        System.out.println("=== notify() vs notifyAll() ===");
        
        Object lock = new Object();
        
        // 创建多个等待线程
        Thread[] waitingThreads = new Thread[3];
        for (int i = 0; i < 3; i++) {
            final int threadId = i;
            waitingThreads[i] = new Thread(() -> {
                synchronized (lock) {
                    try {
                        System.out.println("线程" + threadId + ":开始等待");
                        lock.wait();
                        System.out.println("线程" + threadId + ":被唤醒!");
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }, "WaitingThread-" + i);
        }
        
        // 启动所有等待线程
        for (Thread thread : waitingThreads) {
            thread.start();
        }
        
        Thread.sleep(1000); // 确保所有线程都在等待
        
        // 测试notify() - 只唤醒一个线程
        System.out.println("\n使用notify()唤醒一个线程:");
        synchronized (lock) {
            lock.notify(); // 只唤醒一个线程
        }
        
        Thread.sleep(1000);
        
        // 测试notifyAll() - 唤醒所有线程
        System.out.println("\n使用notifyAll()唤醒所有剩余线程:");
        synchronized (lock) {
            lock.notifyAll(); // 唤醒所有等待的线程
        }
        
        // 等待所有线程完成
        for (Thread thread : waitingThreads) {
            thread.join();
        }
    }
    
    /**
     * 虚假唤醒问题演示
     */
    public static void demonstrateSpuriousWakeup() throws InterruptedException {
        System.out.println("\n=== 虚假唤醒问题 ===");
        
        SpuriousWakeupExample example = new SpuriousWakeupExample();
        
        // 创建消费者线程
        Thread consumer1 = new Thread(example::wrongConsumer, "WrongConsumer");
        Thread consumer2 = new Thread(example::correctConsumer, "CorrectConsumer");
        
        // 创建生产者线程
        Thread producer = new Thread(example::producer, "Producer");
        
        consumer1.start();
        consumer2.start();
        Thread.sleep(100);
        producer.start();
        
        Thread.sleep(5000); // 运行5秒
        
        example.stop();
        
        consumer1.join();
        consumer2.join();
        producer.join();
    }
    
    /**
     * 虚假唤醒示例类
     */
    static class SpuriousWakeupExample {
        private final Object lock = new Object();
        private int items = 0;
        private volatile boolean running = true;
        
        // 错误的消费者实现(使用if)
        public void wrongConsumer() {
            while (running) {
                synchronized (lock) {
                    if (items == 0) { // 错误:使用if
                        try {
                            System.out.println("错误消费者:等待物品");
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    
                    if (items > 0) {
                        items--;
                        System.out.println("错误消费者:消费物品,剩余: " + items);
                    } else {
                        System.out.println("错误消费者:虚假唤醒,没有物品可消费!");
                    }
                }
                
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
        
        // 正确的消费者实现(使用while)
        public void correctConsumer() {
            while (running) {
                synchronized (lock) {
                    while (items == 0 && running) { // 正确:使用while
                        try {
                            System.out.println("正确消费者:等待物品");
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }
                    
                    if (items > 0 && running) {
                        items--;
                        System.out.println("正确消费者:消费物品,剩余: " + items);
                    }
                }
                
                try {
                    Thread.sleep(1200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
        
        public void producer() {
            while (running) {
                synchronized (lock) {
                    items++;
                    System.out.println("生产者:生产物品,总数: " + items);
                    lock.notifyAll(); // 唤醒所有等待的消费者
                }
                
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
        
        public void stop() {
            running = false;
            synchronized (lock) {
                lock.notifyAll();
            }
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        demonstrateNotifyDifference();
        demonstrateSpuriousWakeup();
    }
}

💡 实际应用案例

生产者消费者模式完整实现

public class ProducerConsumerPattern {
    
    /**
     * 使用wait/notify实现的阻塞队列
     */
    static class BlockingQueue<T> {
        private final Object[] queue;
        private final Object lock = new Object();
        private int head = 0;  // 队列头
        private int tail = 0;  // 队列尾
        private int count = 0; // 当前元素数量
        
        public BlockingQueue(int capacity) {
            this.queue = new Object[capacity];
        }
        
        @SuppressWarnings("unchecked")
        public T take() throws InterruptedException {
            synchronized (lock) {
                // 使用while防止虚假唤醒
                while (count == 0) {
                    System.out.println(Thread.currentThread().getName() + ": 队列为空,等待...");
                    lock.wait(); // 等待生产者生产
                }
                
                T item = (T) queue[head];
                queue[head] = null; // 避免内存泄漏
                head = (head + 1) % queue.length;
                count--;
                
                System.out.println(Thread.currentThread().getName() + ": 取出元素,队列大小: " + count);
                
                lock.notifyAll(); // 通知等待的生产者
                return item;
            }
        }
        
        public void put(T item) throws InterruptedException {
            synchronized (lock) {
                // 使用while防止虚假唤醒
                while (count == queue.length) {
                    System.out.println(Thread.currentThread().getName() + ": 队列已满,等待...");
                    lock.wait(); // 等待消费者消费
                }
                
                queue[tail] = item;
                tail = (tail + 1) % queue.length;
                count++;
                
                System.out.println(Thread.currentThread().getName() + ": 放入元素,队列大小: " + count);
                
                lock.notifyAll(); // 通知等待的消费者
            }
        }
        
        public int size() {
            synchronized (lock) {
                return count;
            }
        }
    }
    
    /**
     * 演示生产者消费者模式
     */
    public static void demonstrateProducerConsumer() throws InterruptedException {
        System.out.println("=== 生产者消费者模式演示 ===");
        
        BlockingQueue<String> queue = new BlockingQueue<>(3);
        
        // 创建生产者
        Thread producer1 = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    String item = "Producer1-Item" + i;
                    queue.put(item);
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Producer1");
        
        Thread producer2 = new Thread(() -> {
            try {
                for (int i = 0; i < 3; i++) {
                    String item = "Producer2-Item" + i;
                    queue.put(item);
                    Thread.sleep(800);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Producer2");
        
        // 创建消费者
        Thread consumer1 = new Thread(() -> {
            try {
                for (int i = 0; i < 4; i++) {
                    String item = queue.take();
                    System.out.println("Consumer1 消费: " + item);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Consumer1");
        
        Thread consumer2 = new Thread(() -> {
            try {
                for (int i = 0; i < 4; i++) {
                    String item = queue.take();
                    System.out.println("Consumer2 消费: " + item);
                    Thread.sleep(1200);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Consumer2");
        
        // 启动所有线程
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        
        // 等待所有线程完成
        producer1.join();
        producer2.join();
        consumer1.join();
        consumer2.join();
        
        System.out.println("最终队列大小: " + queue.size());
    }
    
    public static void main(String[] args) throws InterruptedException {
        demonstrateProducerConsumer();
    }
}

📝 最佳实践

使用建议和注意事项

public class BestPractices {
    
    /**
     * wait()使用最佳实践
     */
    public static void waitBestPractices() {
        System.out.println("=== wait()最佳实践 ===");
        
        System.out.println("1. 总是在while循环中使用wait()");
        System.out.println("   while (condition) {");
        System.out.println("       object.wait();");
        System.out.println("   }");
        System.out.println("   原因:防止虚假唤醒");
        
        System.out.println("\n2. 总是在synchronized块中使用wait()");
        System.out.println("   synchronized (object) {");
        System.out.println("       object.wait();");
        System.out.println("   }");
        System.out.println("   原因:wait()需要持有对象的监视器锁");
        
        System.out.println("\n3. 使用notifyAll()而不是notify()");
        System.out.println("   object.notifyAll(); // 推荐");
        System.out.println("   object.notify();    // 可能导致死锁");
        System.out.println("   原因:notify()可能唤醒错误的线程");
        
        System.out.println("\n4. 处理InterruptedException");
        System.out.println("   try {");
        System.out.println("       object.wait();");
        System.out.println("   } catch (InterruptedException e) {");
        System.out.println("       Thread.currentThread().interrupt();");
        System.out.println("       return; // 或其他适当的处理");
        System.out.println("   }");
    }
    
    /**
     * sleep()使用最佳实践
     */
    public static void sleepBestPractices() {
        System.out.println("\n=== sleep()最佳实践 ===");
        
        System.out.println("1. 不要在synchronized块中使用长时间sleep()");
        System.out.println("   synchronized (lock) {");
        System.out.println("       Thread.sleep(10000); // 不好:长时间持有锁");
        System.out.println("   }");
        
        System.out.println("\n2. 处理InterruptedException");
        System.out.println("   try {");
        System.out.println("       Thread.sleep(1000);");
        System.out.println("   } catch (InterruptedException e) {");
        System.out.println("       Thread.currentThread().interrupt();");
        System.out.println("   }");
        
        System.out.println("\n3. 使用TimeUnit提高可读性");
        System.out.println("   TimeUnit.SECONDS.sleep(5); // 更清晰");
        System.out.println("   Thread.sleep(5000);        // 不如上面清晰");
        
        System.out.println("\n4. 考虑使用ScheduledExecutorService");
        System.out.println("   对于定时任务,推荐使用ScheduledExecutorService");
        System.out.println("   而不是Thread.sleep()");
    }
    
    /**
     * 常见错误示例
     */
    public static void commonMistakes() {
        System.out.println("\n=== 常见错误 ===");
        
        System.out.println("❌ 错误1:在if中使用wait()");
        System.out.println("if (condition) { object.wait(); } // 可能虚假唤醒");
        
        System.out.println("\n❌ 错误2:在synchronized块外使用wait()");
        System.out.println("object.wait(); // 抛出IllegalMonitorStateException");
        
        System.out.println("\n❌ 错误3:使用notify()而不是notifyAll()");
        System.out.println("object.notify(); // 可能唤醒错误的线程");
        
        System.out.println("\n❌ 错误4:混淆sleep()和wait()的用途");
        System.out.println("Thread.sleep(1000); // 用于线程通信 - 错误");
        System.out.println("object.wait(1000);  // 用于简单延迟 - 错误");
        
        System.out.println("\n❌ 错误5:不处理InterruptedException");
        System.out.println("try { Thread.sleep(1000); }");
        System.out.println("catch (InterruptedException e) {} // 忽略异常");
    }
    
    public static void main(String[] args) {
        waitBestPractices();
        sleepBestPractices();
        commonMistakes();
    }
}

📝 总结

🎯 核心要点

特性 sleep() wait()
所属 Thread类静态方法 Object类实例方法
锁处理 不释放锁 释放锁
使用位置 任何地方 synchronized块中
唤醒方式 时间到或中断 notify/notifyAll
主要用途 暂停执行 线程通信
典型场景 延迟、轮询 生产者消费者

💡 使用建议

  1. sleep()适用场景

    • 简单的延迟执行

    • 轮询等待某个条件

    • 控制任务执行频率

  2. wait()适用场景

    • 线程间协作通信

    • 生产者消费者模式

    • 条件等待

  3. 最佳实践

    • wait()总是在while循环中使用

    • 优先使用notifyAll()而不是notify()

    • 正确处理InterruptedException

    • 避免在synchronized块中长时间sleep()

⚠️ 注意事项

  • 虚假唤醒:wait()可能在没有notify()的情况下被唤醒

  • IllegalMonitorStateException:wait()必须在synchronized块中

  • 死锁风险:notify()可能唤醒错误的线程

  • 中断处理:正确处理InterruptedException

🚀 进阶学习

  • 学习java.util.concurrent包中的高级工具

  • 了解Condition接口的使用

  • 掌握CountDownLatch、Semaphore等同步工具

  • 学习CompletableFuture异步编程

wait()和sleep()虽然都能让线程暂停,但它们的设计目的和使用场景完全不同。理解它们的区别是掌握Java并发编程的重要一步!


记住:sleep()是为了暂停执行,wait()是为了线程通信。选择正确的工具能让你的并发程序更加健壮。 实践建议:多写生产者消费者的例子,加深对wait/notify机制的理解。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐