💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 简介 多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。 等待唤醒机制所涉及到的方法: ~~~ * wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中 * notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的 * notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。 ~~~ 其实,**所谓唤醒的意思就是让线程池中的线程具备执行资格**。必须注意的是,这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。 仔细查看JavaAPI之后,发现这些方法 并不定义在 Thread中,也没定义在Runnable接口中,却被定义在了Object类中,为什么这些操作线程的方法定义在Object类中? 因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。 ~~~ void notify() 唤醒在此对象监视器上等待的单个线程 void notifyAll() 唤醒在此对象监视器上等待的所有线程 void wait() 在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待 ~~~ # 例子 ![](https://box.kancloud.cn/b2568a630f6681c57289bb39dc86f78a_931x329.png) 如上图说示,输入线程向Resource中输入name ,sex , 输出线程从资源中输出,先要完成的任务是: * 1.当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait(); * 2.当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。 那个对象等待的就用那个对象唤醒 下面代码,模拟等待唤醒机制的实现 * 模拟资源类 ~~~ public class Resource { private String name; private String sex; private boolean flag = false; public synchronized void set(String name, String sex) { //这边不是if else, wait之后,唤醒要set,不然少一次set if (flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 设置成员变量 this.name = name; this.sex = sex; // 设置之后,Resource中有值,将标记该为 true , flag = true; // 唤醒output this.notify(); } public synchronized void out() { if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 输出线程将数据输出 System.out.println("姓名: " + name + ",性别: " + sex); // 改变标记,以便输入线程输入数据 flag = false; // 唤醒input,进行数据输入 this.notify(); } } ~~~ * 输入线程任务类 ~~~ public class Input implements Runnable { private Resource r; public Input(Resource r) { this.r = r; } @Override public void run() { int count = 0; while (true) { if (count == 0) { r.set("小明", "男生"); } else { r.set("小花", "女生"); } // 在两个数据之间进行切换 count = (count + 1) % 2; } } } ~~~ * 输出线程任务类 ~~~ public class Output implements Runnable { private Resource r; public Output(Resource r) { this.r = r; } @Override public void run() { while (true) { r.out(); } } } ~~~ * 测试类 ~~~ public class ResourceDemo { public static void main(String[] args) { // 资源对象 Resource r = new Resource(); // 任务对象 Input in = new Input(r); Output out = new Output(r); // 线程对象 Thread t1 = new Thread(in); Thread t2 = new Thread(out); // 开启线程 t1.start(); t2.start(); } } ~~~ # wait带参数 进入TimeWaiting(计时等待)有两种方式 1. 使用sleep(Long m)方法,在毫秒值结束后,线程睡眠后进入到Runnable/Blocked状态 2. 使用wait(Long m)方法,wait方法如果在毫秒值结束后,还没有被notify唤醒,就自动醒来,线程睡醒进入Runnable/Blocked状态 # sleep和wait区别 1. 方法声明 ~~~ Thread.sleep() ~~~ ~~~ Object.sleep() ~~~ 2. 共同点 当前线程进入阻塞状态 3. 使用范围 sleep使用没有情景要求, wait必须在同步代码块或同步方法中 4. 都在同步中用 wait需要唤醒,会释放锁 sleep不需要唤醒,不会释放锁