多线程|wait、notify的使用
线程执行顺序的随机性的根本原因是随机调度和抢占式执行,但在开发的过程中,我们往往希望代码按照一定的顺序执行,因此Java中提供了一些可以控制线程执行顺序的方法,通过这些方法让线程主动阻塞,让出CPU资源。wait搭配notify使用就可以控制线程的执行顺序。
wait和notify如何使用呢?我们借助代码来说明。
public static void main(String[] args) { Object object = new Object(); Thread t1 = new Thread(() ->{ System.out.println("t1:wait之前"); try{ object.wait(); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("t1:wait之后"); }); Thread t2 = new Thread(() ->{ System.out.println("t2:notify之前"); object.notify(); System.out.println("t2:notify之后"); }); t1.start(); t2.start(); }
梳理上述代码的思路:首先明确wait、notify都是Object类的方法,因此在使用wait和notify的时候,要先创建Object对象再去调用。创建线程t1,调用wait方法,让线程t1进入阻塞,创建线程t2,调用notify方法唤醒线程t1,来看看执行结果:
执行结果出现了非法的锁状态异常,为什么有这个异常?来看看wait的工作原理:
1、释放锁;
2、进行阻塞;
3、收到notify通知后,重新尝试锁,获取锁后,继续往下执行。
wait和notify的使用必须搭配锁来使用,我们在相应位置加上锁:
public static void main(String[] args) throws InterruptedException { Object object = new Object(); Thread t1 = new Thread(() -> { System.out.println("t1 : wait之前"); synchronized (object){ try{ object.wait(); }catch (InterruptedException e){ e.printStackTrace(); } System.out.println("t1 :wait之后"); } }); Thread t2 = new Thread(() -> { System.out.println("t2 : notify之前"); synchronized (object){ object.notify(); } System.out.println("t2 :notify之后"); }); t1.start(); t2.start(); }
我们看看执行结果:
从结果可以看到,t2线程先t1线程执行,t2线程执行到notify时,会去唤醒wait,但问题是此时线程t1中的wait还未执行到,那么此时notify就是没有作用的,而当线程t1执行到wait时,由于没有notify来唤醒,所以就一直在阻塞等待。当然了,线程的随机调度也有可能先调度执行线程t1,再执行t2,notify就能发挥作用,但是我们想每次执行时都要t1线程先执行,此时的解决办法是在t2.start()之前调用sleep()。
此时sleep(500)大概率会让t1线程执行到wait的,但是极端情况下,电脑非常卡的情况下,线程的调度时间可能超过500ms,那此时sleep也是没有作用的。我们再来看看最终的代码通常情况下的执行结果:
我们再次梳理代码的逻辑,创建线程t1,在t1线程中调用wait,创建线程t2,调用notify唤醒线程t1,t1线程被唤醒之后,继续往下执行,也就是打印输出“t1:wait”之后,而上述的执行效果都是基于t1线程先执行的前提下才能实现的,由于线程的随机调度,线程t2有可能先于t1线程执行,执行到notify,若现在线程1还没执行到wait,那么此时notify是没有任何作用的,因此必须得让t1线程先执行到wait,解决方法是在t2.start()之前调用sleep,以保证t1线程执行到wait。
注意:调用wait的对象和锁对象必须是同一个对象,同理notify也是一样的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix