Java等待的基本概念

Java多线程编程中,"等待"是一个核心概念,它指的是线程暂停执行,直到满足特定条件后再继续运行。Java提供了多种等待机制,每种机制都有其特定的使用场景和优势。

Java等待机制:深入理解线程同步与等待策略

为什么需要等待机制

多线程环境中,线程间的协调至关重要。当多个线程共享资源或需要按特定顺序执行时,等待机制可以:
- 避免资源竞争
- 提高程序效率
- 确保线程安全
- 实现线程间的通信

Java中的主要等待方式

Java平台提供了三种主要的等待实现方式:
1. Object.wait()方法
2. Thread.sleep()方法
3. LockCondition接口

Object.wait()方法详解

Object.wait()是Java中最基础的等待机制,它允许线程释放对象锁并进入等待状态,直到其他线程调用该对象的notify()notifyAll()方法。

Java等待机制:深入理解线程同步与等待策略

wait()方法的基本用法

```java
synchronized (sharedObject) {
while (!condition) {
sharedObject.wait();
}
// 执行条件满足后的操作
}


### wait()方法的三个重要特性

1. **释放锁**:调用wait()会立即释放对象锁
2. **等待通知**:线程会保持等待直到收到通知
3. **虚假唤醒**:可能在没有通知的情况下被唤醒,因此条件检查应在循环中进行

### wait()与notify()的配合使用

```java
// 等待线程
synchronized (lock) {
    while (!ready) {
        lock.wait();
    }
    System.out.println("继续执行");
}

// 通知线程
synchronized (lock) {
    ready = true;
    lock.notifyAll();
}

Thread.sleep()方法分析

虽然Thread.sleep()也能实现等待效果,但它与Object.wait()有本质区别。

sleep()的特点

  • 不会释放任何锁
  • 不需要在同步块中调用
  • 只是让当前线程暂停执行指定时间
  • 不能被中断(会抛出InterruptedException)

sleep()的典型使用场景

// 简单延时
try {
    Thread.sleep(1000); // 暂停1秒
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

高级等待机制:Lock和Condition

Java 5引入的java.util.concurrent.locks包提供了更灵活的等待机制。

Java等待机制:深入理解线程同步与等待策略

Lock接口的优势

  • 更细粒度的锁控制
  • 可以尝试获取锁
  • 支持公平锁
  • 支持多个Condition

Condition的使用示例

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

// 等待线程
lock.lock();
try {
    while (!conditionMet) {
        condition.await();
    }
    // 执行操作
} finally {
    lock.unlock();
}

// 通知线程
lock.lock();
try {
    conditionMet = true;
    condition.signal();
} finally {
    lock.unlock();
}

Java等待的最佳实践

避免常见的等待陷阱

  1. 忘记在循环中检查条件:可能导致虚假唤醒问题
  2. 错误处理InterruptedException:应恢复中断状态
  3. 持有锁时间过长:影响程序性能
  4. 过度使用sleep():可能导致响应性问题

性能优化建议

  1. 优先使用notifyAll()除非确定只有一个等待线程
  2. 考虑使用java.util.concurrent包中的高级工具类
  3. 对于超时等待,使用带有超时参数的wait()方法
  4. 在适当场景下考虑使用自旋锁

Java 8及以后版本中的等待改进

CompletableFuture提供的异步等待

CompletableFuture.supplyAsync(() -> {
    // 异步任务
}).thenAccept(result -> {
    // 结果处理
}).join(); // 等待完成

新的并发工具类

  • StampedLock:改进的读写锁
  • Phaser:更灵活的同步屏障
  • ForkJoinPool:工作窃取线程池

实际应用案例:生产者消费者问题

使用wait/notify实现

class Buffer {
    private Queue<Integer> queue = new LinkedList<>();
    private int capacity;

    public Buffer(int capacity) {
        this.capacity = capacity;
    }

    public synchronized void produce(int item) throws InterruptedException {
        while (queue.size() == capacity) {
            wait();
        }
        queue.add(item);
        notifyAll();
    }

    public synchronized int consume() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        int item = queue.remove();
        notifyAll();
        return item;
    }
}

使用Lock和Condition实现

class Buffer {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    // 其余代码类似,使用await/signal代替wait/notify
}

总结与选择指南

Java提供了丰富的等待机制,选择哪种方式取决于具体需求:

  1. 简单同步:使用synchronized配合wait/notify
  2. 定时等待:使用带有超时参数的wait()sleep()
  3. 高级控制:使用LockCondition
  4. 异步编程:考虑CompletableFuture
  5. 高性能场景:探索java.util.concurrent中的高级工具

理解这些等待机制的区别和适用场景,是编写高效、可靠多线程Java程序的关键。

《Java等待机制:深入理解线程同步与等待策略》.doc
将本文下载保存,方便收藏和打印
下载文档