Java线程的通信

本文最后更新于 2024年11月5日

当需要多个线程共同完成一件任务,而且需要有规律的执行,那么多个线程之间需要一定的通信机制,可以协调他们的工作,以此实现多线程共同操作一份数据。

1 等待唤醒机制

这是一种线程间的协作机制,与争夺锁的竞争机制相对应,当一个线程满足某个条件时,就进入等待状态( wait/wait(m) ),等到其他线程执行完指定的代码后,再将其唤醒,或者可以指定时间,到时间了自动唤醒,有多个线程等待时,如果有需要,可以notifyAll()唤醒所有等待的线程,wait/notify就是一种线程间的协助机制。

wait()

  • 作用:使当前线程等待,直到其他线程调用相同对象的 notify()notifyAll() 方法,或者线程被中断。
  • 使用场景:当一个线程需要等待某个条件发生时,比如资源可用、状态改变等。
  • 条件:调用 wait() 方法时,当前线程必须持有该对象的监视器锁(synchronized),否则会抛出 IllegalMonitorStateException 异常。
synchronized (sharedObject) {
    while (!condition) {
        sharedObject.wait(); // 释放锁并等待
    }
    // 条件满足后的操作
}

notify()

  • 作用:唤醒在该对象上等待的一个线程。如果有多个线程在等待,则随机选择一个线程唤醒。
  • 使用场景:在某个条件被满足时,通知一个等待的线程继续执行。
synchronized (sharedObject) {
    // 修改条件
    sharedObject.notify(); // 唤醒一个等待线程
}

notifyAll()

  • 作用:唤醒在该对象上等待的所有线程。
  • 使用场景:当条件变化可能影响所有等待线程时,使用 notifyAll() 确保所有线程都有机会重新检查条件。
synchronized (sharedObject) {
    // 修改条件
    sharedObject.notifyAll(); // 唤醒所有等待线程
}

2 例子

2.1 两个线程共同卖票,一人一张


public class Ticket {

    public static void main(String[] args) {

        TicketTask t1 = new TicketTask();
        TicketTask t2 = new TicketTask();

        t1.start();
        t2.start();

    }

    static class TicketTask extends Thread {

        static int ticket = 200;
        static final Object lock = new Object();

        @Override
        public void run() {
            while (true) {

                synchronized (lock) {
                    lock.notifyAll();

                    if (ticket > 0) {
                        System.out.println(Thread.currentThread().getName() +" " + ticket);
                        ticket--;
                    }
                    else {
                        break;
                    }

                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }

            }
        }
    }
}

2.2 两个线程共同交替从1加到100

public class TestAdd {

    static int i = 0;

    public static void main(String[] args) {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (this){
                        this.notify();
                        if (i < 100) {
                            System.out.println(Thread.currentThread().getName() + "---" + ++i);
                        }
                        else {
                            break;
                        }

                        try {
                            this.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }

                }

            }
        };

        new Thread(runnable).start();
        new Thread(runnable).start();

    }
    
}

Java线程的通信
https://blog.liuzijian.com/post/10e497bb-feb5-f9fb-a256-428f0041960e.html
作者
Liu Zijian
发布于
2022年5月1日
更新于
2024年11月5日
许可协议