为什么从同步块调用 `wait` 和 `notify` 方法?

简介: 【8月更文挑战第22天】

在 Java 中,waitnotify 方法是 Object 类提供的用于线程间通信和同步的关键方法。它们必须在 同步块同步方法 中调用,原因如下:

线程安全

同步块或同步方法确保同一时刻只有一个线程可以访问共享资源或代码块。当一个线程调用 wait 方法时,它会释放锁并进入 等待 状态,直到被另一个线程调用 notifynotifyAll 方法唤醒。

如果 waitnotify 方法不在同步块或同步方法中调用,则可能导致 竞争条件。例如,如果一个线程调用 wait 方法后,另一个线程在没有获得锁的情况下修改了共享资源,则第一个线程在被唤醒后可能会使用过时的或不一致的数据。

死锁避免

死锁是指两个或多个线程互相等待对方释放锁的情况,导致所有线程都被阻塞。如果 waitnotify 方法不在同步块或同步方法中调用,则可能导致死锁。

例如,考虑以下代码:

public class DeadlockExample {
   
    private Object lock = new Object();

    public void method1() {
   
        synchronized (lock) {
   
            // 执行任务 1
        }
    }

    public void method2() {
   
        // 没有同步块
        lock.wait();
    }
}

在这个示例中,method1() 是一个同步方法,而 method2() 没有同步块。如果线程 1 调用 method1() 并获得锁,然后线程 2 调用 method2(),则线程 2 将一直等待,因为线程 1 还没有释放锁。同时,线程 1 也无法继续执行,因为它正在等待线程 2 释放锁。这将导致死锁。

最佳实践

为了避免竞争条件和死锁,始终在同步块或同步方法中调用 waitnotify 方法。这将确保在同一时间只有一个线程可以访问共享资源或执行代码块,从而保证线程安全和避免死锁。

示例

以下代码演示了如何正确地在同步块中调用 waitnotify 方法:

public class ThreadCommunication {
   
    private Object lock = new Object();
    private boolean ready = false;

    public void producer() {
   
        synchronized (lock) {
   
            while (!ready) {
   
                try {
   
                    lock.wait();
                } catch (InterruptedException e) {
   
                    // 处理中断
                }
            }

            // 生产数据

            // 唤醒消费者线程
            lock.notify();
        }
    }

    public void consumer() {
   
        synchronized (lock) {
   
            while (!ready) {
   
                try {
   
                    lock.wait();
                } catch (InterruptedException e) {
   
                    // 处理中断
                }
            }

            // 消费数据
        }
    }
}

在这个示例中,生产者线程在 producer() 方法中使用一个同步块来确保在生产数据之前不会被唤醒。消费者线程在 consumer() 方法中也使用一个同步块来确保在数据准备好之前不会被唤醒。这样可以防止竞争条件和死锁。

总结

从同步块或同步方法调用 waitnotify 方法对于确保线程安全和避免死锁至关重要。通过遵循此最佳实践,可以编写健壮且可行的多线程应用程序。

目录
相关文章
|
28天前
|
安全 Java 开发者
Java中WAIT和NOTIFY方法必须在同步块中调用的原因
在Java多线程编程中,`wait()`和`notify()`方法是实现线程间协作的关键。这两个方法必须在同步块或同步方法中调用,这一要求背后有着深刻的原因。本文将深入探讨为什么`wait()`和`notify()`方法必须在同步块中调用,以及这一机制如何确保线程安全和避免死锁。
41 4
|
4月前
|
安全 Java 调度
为什么 wait 方法要在 synchronized 中调用?
它们是在有 synchronized 标记的方法或 synchronized 块中调用的,因为 wait 和 nodify 需要监视对其调用的 Object。 大多数Java开发人员都知道对象类的 wait(),notify() 和 notifyAll() 方法必须在 Java 中的 synchronized 方法或 synchronized 块中调用, 但是我们想过多少次, 为什么在 Java 中 wait, notify 和 notifyAll 来自 synchronized 块或方法?
198 0
为什么 wait 方法要在 synchronized 中调用?
为什么 wait, notify 和 notifyAll 这些方法不在 thread 类里面?
为什么 wait, notify 和 notifyAll 这些方法不在 thread 类里面?
295 0
Zp
wait,notify,notifyAll原理以及实际使用场景
wait,notify,notifyAll原理以及实际使用场景
Zp
246 0
|
Go
Go channel被关闭时的广播机制,以及遍历未关闭channel时会导致死锁阻塞问题
Go channel被关闭时的广播机制,以及遍历未关闭channel时会导致死锁阻塞问题
186 0
|
Java 调度
join线程执行结束之后,并没有看到哪里有notify方法,请问此时谁去唤醒等待池中的线程
Java中的join方法,阻塞当前线程,直到join线程结束后才继续执行。底层是通过wait来实现的,join线程执行结束之后,并没有看到哪里有notify方法,请问此时谁去唤醒等待池中的线程(join之前的那个“当前”线程)呢?
105 0
join线程执行结束之后,并没有看到哪里有notify方法,请问此时谁去唤醒等待池中的线程
|
调度
【多线程:wait/notify详解】原理及错误用法(虚假唤醒等)
【多线程:wait/notify详解】原理及错误用法(虚假唤醒等)
205 0
|
消息中间件 调度
RT-Thread记录(六、IPC机制之信号量、互斥量和事件集)
上文说到 RT-Thread 对临界区的处理方式有多种,其中已经分析了关闭调度器和屏蔽中断的方式, 本文就来学学另外的线程同步方式。
735 0
RT-Thread记录(六、IPC机制之信号量、互斥量和事件集)