博客
关于我
Java多线程wait()和notify()系列方法使用教程(内涵故事)
阅读量:673 次
发布时间:2019-03-15

本文共 2859 字,大约阅读时间需要 9 分钟。

Java wait()和notify()方法实用解析

在Java中,wait()notify()方法是线程编程中的强大工具,用于实现线程间的等待与唤醒机制。它们被ictionary对象提供,是线程安全编程的基础之一。本文将通过两个线程的互动案例,详细解析这两个方法的工作原理及其使用规范。

一、方法概述

  • wait()方法:使当前线程等待。这意味着线程不会再竞争任何与当前共享对象相关的锁定。这一机制可以节省CPU资源,让线程暂停执行,等待某一特定条件的满足。
  • wait(long timeout)方法:带有超时参数的等待方法。若在指定时间内没有被notify()唤醒,超时会被自动抛出。传递负值时,会抛出IllegalStateException。默认情况下,参数为0,表示无限等待。
  • notify()方法:唤醒当前线程中等待共享对象锁定的线程之一。notify()通知的线程会立即返回,重新参与线程调度,但不会立即获得锁。
  • notifyAll()方法:唤醒所有等候共享对象锁定的线程。与queue方法类似,但作用范围更大。

使用这些方法需要遵循一定规则:

  • 区域同步:所有涉及共享对象的操作必须在同步块内,这确保了线程安全。
  • 单例对象:这些方法仅针对单个共享对象生效。如果需要同时等待多个共享对象,需重复调用wait()
  • 中断处理:若在等待期间,线程被中断,会抛出InterruptedException异常,需确保该异常被正确处理。
  • 二、典型案例解析

    为了直观理解wait()notify()的工作机制,我们设计了一个简单的示例场景:

    需求:让一个线程等待,而另一个线程在等待期间进行某种操作,并在完成后唤醒等待线程。

    步骤

  • 创建共享对象:确保多个线程能进行互动。
  • 启动线程:分别启动Thread0Thread1,分别执行不同的操作。
  • Thread0执行wait():当前线程获得锁,并进入等待状态。
  • Thread1获得锁,执行notify():在自己的操作完成后,唤醒等待的Thread0
  • Thread0恢复执行:重获锁定,继续后续操作。
  • 示例代码

    public class ThreadWaitAnd Notify {    private static Object object = new Object(); // 共享对象    static class Thread0 extends Thread {        @Override        public void run() {            synchronized (object) {                System.out.println("Thread-0:获得锁,执行wait()...");                 object.wait(); // 线程进入等待状态                System.out.println("Thread-0:从wait()恢复执行");            }        }    }    static class Thread1 extends Thread {        @Override        public void run() {            synchronized (object) {                System.out.println("Thread-1:获得锁,执行 notify()...");                 object.notify(); // 唤醒等待的线程                System.out.println("Thread-1:完成 notify()操作");            }        }    }    public static void main(String[] args) {        Thread0 thread0 = new Thread0();        Thread1 thread1 = new Thread1();        try {            thread0.start();            Thread.sleep(500); // 给Thread1时间先启动            thread1.start();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

    运行输出

    Thread-0:获得锁,执行wait()...Thread-1:获得锁,执行 notify()...Thread-1:完成 notify()操作Thread-0:从wait()恢复执行

    这段输出明确展示了线程的等待与唤醒过程:

  • Thread-0获取共享对象锁,调用wait()后立即退出同步块,进入等待状态。
  • Thread-1启动,成功获取锁,调用notify(),通知Thread-0解除等待。
  • Thread-1离开同步块,(thread-0)随后恢复执行。
  • 三、线程的等待唤醒机制

    从示例中可以看到,wait()notify()的核心机制包括:

  • 线程交替:在获取锁后,Thread-0暂停执行,等待消息;Thread-1获得锁,修改状态,然后唤醒Thread-0
  • 资源释放:在执行完相关操作后,Thread-1归还锁;等待的Thread-0随后重新获取锁,继续执行。
  • 效率与资源:这种机制允许多个线程轮转使用唯一资源,最大化资源利用率。
  • 注意事项

  • 同步机制:所有与共享对象相关的操作都必须在同步块内修饰。否则,可能导致竞态条件或其他线程安全问题。
  • 资源分配:如果有多个共享对象,需要分别调用wait()方法,确保每个对象都能被正确管理。
  • 中断处理:在等待期间,若线程被中断,必须在catch块中妥善处理InterruptedException异常,避免死锁或逻辑错误。
  • 四、与生活场景对应的故事

    前文提到的“捡肥皂”故事,相当于一个简单的资源共享场景:

    • 王哥和李哥:一个拿到肥皂后,不断使用直到完成任务,随后归还资源,另一个线程可以接着使用。这种方式确保了资源的高效利用。
    • 小王和小李:双方“抢夺”肥皂,虽然并不真正等待,但资源分配显然不够优雅,容易引发冲突。

    网页内容提到的“老王和老李”,则是最理想的情况:

    • 他们不仅能够高效共享资源,还能灵活分配使用。

    五、总结

    通过示例和生活化的类比,我们可以清晰地看到wait()notify()方法的作用及其重要性。要正确使用这些方法,需遵守线程安全的原则,并结合实际场景进行合理设计。理解这些方法的使用场景,将有助于我们更好地设计和实现高效的多线程应用程序。

    欢迎转载和分享!

    你可能感兴趣的文章
    MySQL 到底能不能放到 Docker 里跑?
    查看>>
    mysql 前缀索引 命令_11 | Mysql怎么给字符串字段加索引?
    查看>>
    mysql 协议的退出命令包及解析
    查看>>
    mysql 取表中分组之后最新一条数据 分组最新数据 分组取最新数据 分组数据 获取每个分类的最新数据
    查看>>
    mysql 四种存储引擎
    查看>>
    MySQL 基础模块的面试题总结
    查看>>
    MySQL 备份 Xtrabackup
    查看>>
    mysql 多个表关联查询查询时间长的问题
    查看>>
    mySQL 多个表求多个count
    查看>>
    mysql 多字段删除重复数据,保留最小id数据
    查看>>
    MySQL 多表联合查询:UNION 和 JOIN 分析
    查看>>
    MySQL 大数据量快速插入方法和语句优化
    查看>>
    mysql 如何给SQL添加索引
    查看>>
    mysql 字段区分大小写
    查看>>
    mysql 字段合并问题(group_concat)
    查看>>
    mysql 字段类型类型
    查看>>
    MySQL 字符串截取函数,字段截取,字符串截取
    查看>>
    MySQL 存储引擎
    查看>>
    mysql 存储过程 注入_mysql 视图 事务 存储过程 SQL注入
    查看>>
    MySQL 存储过程参数:in、out、inout
    查看>>