Java多线程通信:wait、notify与共享对象实践

0 下载量 144 浏览量 更新于2024-09-02 收藏 98KB PDF 举报
Java多线程线程通信是实现并发编程中关键的一环,它使得多个线程能够协作完成复杂的任务。本文将深入探讨几种线程通信的方式,并通过示例代码来帮助理解。 1. **通过共享对象通信** 线程间的通信往往基于共享数据,通过修改共享对象的状态来传递信号。如在`MySignal`类中,`hasDataToProcess`变量被用来作为通信的标志。线程A在合适的时候将`hasDataToProcess`设为true,而线程B则通过同步访问该变量来判断是否可以继续执行。这种方式简单但可能会引发竞态条件,需要配合synchronized关键字确保数据同步。 ```java public class MySignal { protected boolean hasDataToProcess = false; public synchronized boolean hasDataToProcess() { return this.hasDataToProcess; } public synchronized void setHasDataToProcess(boolean hasData) { this.hasDataToProcess = hasData; } } ``` 2. **忙等待(Busy Wait)** 忙等待是指一个线程不断地检查某个条件是否满足,直到满足为止。例如,线程B在`sharedSignal.hasDataToProcess()`返回true时才停止循环。这种做法虽然简单,但会消耗大量CPU资源,因为它始终处于活动状态。 ```java while (!sharedSignal.hasDataToProcess()) { // do nothing, busy waiting } ``` 3. **wait(),notify()和notifyAll()** Java中的`wait()`、`notify()`和`notifyAll()`是Object类的方法,用于线程间的同步和通信。在线程A设置完数据后,可以调用`notify()`或`notifyAll()`唤醒等待的线程B。线程B在等待时调用`wait()`,将其放入等待队列,释放对象锁并进入等待状态。当线程A调用`notify()`或`notifyAll()`时,会随机选择一个等待线程唤醒(`notify()`)或唤醒所有等待线程(`notifyAll()`)。需要注意的是,这些操作必须在同步块或同步方法中进行,以避免异常。 ```java synchronized (sharedSignal) { while (!sharedSignal.hasDataToProcess()) { sharedSignal.wait(); } // process data sharedSignal.setHasDataToProcess(false); sharedSignal.notify(); // 或者 notifyAll() } ``` 4. **丢失的信号** 在多线程环境中,线程可能会错过其他线程发出的信号。比如,线程A在调用`notify()`之后立即结束,而线程B尚未进入`wait()`状态,那么信号就丢失了。为避免这种情况,通常需要确保调用`wait()`的线程在被唤醒后能重新检查条件。 5. **假唤醒(Spurious Wakeup)** 虽然Java规范保证了`wait()`不会因非`notify()`或`notifyAll()`事件而被唤醒,但在实际应用中可能出现假唤醒的情况。因此,等待线程应该总是在被唤醒后重新检查条件。 6. **多线程等待相同信号** 当多个线程等待同一信号时,`notify()`只会唤醒一个线程,而`notifyAll()`会唤醒所有线程。根据具体需求选择合适的方法。 7. **不要对常量字符串或全局对象调用wait()** 对于常量字符串或其他全局对象,多个线程可能共享相同的引用,这时调用`wait()`可能导致不可预期的行为。每个需要等待的线程应持有独立的锁对象。 Java多线程的线程通信是通过共享数据、使用`wait()`、`notify()`和`notifyAll()`等方法实现的。在实际编程中,理解这些通信机制并正确使用是保证多线程程序正确性和效率的关键。同时,还需要注意避免竞态条件、死锁和资源浪费等问题。