行业资讯 2025年08月6日
0 收藏 0 点赞 560 浏览 3141 个字
摘要 :

文章目录 等待/通知机制概念 等待/通知机制实现 wait()代码实例: wait()/notify()代码示例: interrupt()方法会中断wait() wait(long)方法的使用 notify()和notifyAl……




  • 等待/通知机制概念
  • 等待/通知机制实现
  • wait()代码实例:
  • wait()/notify()代码示例:
  • interrupt()方法会中断wait()
    • wait(long)方法的使用
  • notify()和notifyAll()的区别

本文主要重点讲解Java多线程线程间通信(等待/通知机制)问题。

等待/通知机制概念

等待/通知机制在我们生活中比比皆是,一个形象的例子就是厨师和服务员之间就存在等待/通知机制。

  1. 厨师做完一道菜的时间是不确定的,所以菜到服务员手中的时间是不确定的;
  2. 服务员就需要去“等待(wait)”;
  3. 厨师把菜做完之后,按一下铃,这里的按铃就是“通知(nofity)”;
  4. 服务员听到铃声之后就知道菜做好了,他可以去端菜了。

在Java多线程中理解就是:

等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()/notifyAll()方法,线程A收到通知后退出等待队列,进入可运行状态,进而执行后续操作。上面这样的一个过程就是等待/通知机制。

等待/通知机制实现

Object类中的wait()方法,可以使执行当前代码的线程等待,暂停执行。直到接到通知或被中断为止。

注意:wait()方法只能在同步代码块中由锁对象调用,且调用wait()方法后,当前线程会释放锁。

Object类的notify()方法可以唤醒处于等待的线程,该方法也必须在同步代码块中由锁对象调用。如果有多个等待的线程,notify()只能唤醒其中一个,具体唤醒哪一个是不知道的。被notify()的线程需要重新去竞争锁才能被执行。

没有使用锁对象就调用wait()/notify()方法会产生异常:IllegalMonitorStateException。

wait()代码实例:

public class Test01 {

    public static void main(String[] args) throws InterruptedException {
        String test = \"abc\";
        String another = \"def\";
        System.out.println(\"同步代码块前的代码\");
        synchronized (test) {
            try {
                System.out.println(\"wait前的代码\");
                // another.wait();  只有被锁住的对象才能调用wait()方法
                test.wait();
                System.out.println(\"wait后的代码\");
            } catch (IllegalMonitorStateException e) {
                e.printStackTrace();
            }
        }
        System.out.println(\"同步代码块后的代码\");
    }
}

wait()/notify()代码示例:

/**
 * 需要通过notify唤醒线程
 */
public class Test02 {

    public static void main(String[] args) {
        String str = \"wa\";

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (str) {
                    System.out.println(\"线程1开始等待\");
                    try {
                        str.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(\"线程1被唤醒并执行结束了\");
                }
            }
        }, \"Thread1\");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (str) {
                    System.out.println(\"线程2唤醒线程1\");
                    str.notify();
                }
            }
        }, \"Thread2\");

        thread1.start();
        thread2.start();
    }
}

执行了notify()的线程并不会立即释放锁,而是执行完同步代码块的所有代码后才会释放锁

interrupt()方法会中断wait()

当线程调用wait()处于等待状态时,调用线程对象的interrupt()方法会中断线程的等待状态,产生InterruptedException异常。

/**
 * interrupt()会中断线程的wait状态
 */
public class Test04 {
    public static void main(String[] args) throws InterruptedException {
        SubThread subThread = new SubThread();
        subThread.start();
        TimeUnit.SECONDS.sleep(1);
        subThread.interrupt();
    }

    private static final Object lock = new Object();

    static class SubThread extends Thread {
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(\"subThread wait\");
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    System.out.println(\"wait等待被中断了\");
                }
                System.out.println(\"subThread end wait\");
            }
        }
    }
}

wait(long)方法的使用

如果在指定时间内没有被唤醒,那么线程会自动唤醒。

public class Test06 {
    public static void main(String[] args) {
        SubThread subThread = new SubThread();
        subThread.start();
    }

    static final Object lock = new Object();

    static class SubThread extends Thread{
        @Override
        public void run() {
            synchronized (lock) {
                try {
                    System.out.println(\"开始等待\");
                    lock.wait(5000);
                    System.out.println(\"等待结束\");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

notify()和notifyAll()的区别

1) 唤醒数量不同

notify()方法只会随机唤醒等待队列中的一个线程,而notifyAll()方法则会唤醒等待队列中的所有线程。

2)调用方式不同

notify()和notifyAll()方法都必须在同步代码块中调用,并且必须包含在synchronized块中,且必须是该对象的监视器对象才能够调用。而且只有在获取了锁之后才能调用,否则会抛出IllegalMonitorStateException异常。

3) 竞争情况不同

notify()方法只会唤醒等待队列中的一个线程,并使其与其他线程竞争获取锁,这可能会导致某些线程无法被唤醒或者一直处于等待状态。

notifyAll()方法则会唤醒等待队列中的所有线程,并使它们竞争获取锁,这样可以使所有线程都有机会获取锁并进入运行状态,从而避免了一些线程一直处于等待状态。

总结

以上就是Java多线程:线程间通信(等待/通知机制)的基础内容,如下想要更深层次地理解该机制,可以参考下一篇文章:Java多线程:线程间通信(生产者消费者模式)

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/9679.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号