Java 多线程唤醒

在Java中,多线程是一种强大的编程模型,它允许我们同时执行多个任务,以提高程序的并发性和性能。然而,在多线程编程中,我们经常会遇到需要一个线程等待另一个线程完成特定任务后才能继续执行的情况。为了实现这种线程间的协作,Java提供了一些机制,如wait()和notify()方法,用于线程的等待和唤醒。

等待与唤醒

在Java中,每个对象都有一个等待队列,用于存放等待该对象的线程。当一个线程调用一个对象的wait()方法时,它将会被放入该对象的等待队列中,并释放对该对象的锁。这个线程会一直等待,直到其他线程调用相同对象的notify()或notifyAll()方法来将其唤醒。

当一个线程调用一个对象的notify()方法时,它将会随机选择一个等待该对象的线程,并将其从等待队列中移除,并重新获取对该对象的锁。被唤醒的线程将会继续执行wait()方法之后的代码,直到结束或再次被阻塞。

与notify()方法不同,notifyAll()方法将会唤醒等待该对象的所有线程,使它们竞争获取该对象的锁。

代码示例

下面是一个简单的示例,演示了多线程的等待和唤醒过程:

public class WaitNotifyExample {
    public static void main(String[] args) {
        final Object lock = new Object();

        // 线程A
        Thread threadA = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread A is waiting");
                    lock.wait(); // 线程A等待并释放锁
                    System.out.println("Thread A is resumed");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 线程B
        Thread threadB = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread B is running");
                lock.notify(); // 唤醒等待该对象的线程
            }
        });

        threadA.start(); // 启动线程A
        try {
            Thread.sleep(1000); // 等待一段时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadB.start(); // 启动线程B
    }
}

在上面的示例中,我们创建了两个线程A和B。线程A在获取锁后,调用了对象的wait()方法,进入等待状态并释放锁。而线程B在获取锁后,调用了对象的notify()方法,将线程A唤醒,并继续执行后续代码。

运行上述代码,你可能会看到以下输出:

Thread A is waiting
Thread B is running
Thread A is resumed

关于计算相关的数学公式

在多线程编程中,使用数学公式可以帮助我们更好地理解线程的等待和唤醒机制。下面是一个示例公式,用于描述等待和唤醒的关系:

唤醒 = 等待 / 竞争

在这个公式中,等待表示线程等待的时间,而竞争表示线程之间竞争的时间。当竞争越激烈时,唤醒的频率就会更高,线程等待的时间就会越短。

流程图

下面是一个流程图,描述了线程的等待和唤醒过程:

st=>start: 开始
op1=>operation: 获取锁
op2=>operation: 等待并释放锁
op3=>operation: 唤醒并重新获取锁
e=>end: 结束

st->op1->op2->op3->e

在这个流程图中,我们首先获取锁,然后调用wait()方法进入等待状态并释放锁。当其他线程调用notify()方法唤