🏀🏀🏀来都来了,不妨点个关注!
🎧🎧🎧博客主页:欢迎各位大佬!
文章目录
1. 为什么需要wait()和notify()
在上一篇关于线程安全的问题中,我们提到过线程的调度是无序的,随机的,但很多时候我们都不喜欢随机的东西,很多时候都需要线程能有序的执行,此时就用到了我们今天要介绍的两个方法,wait()和notify()。相信大家都去银行的取款机取过钱,就算没有,也大致知道是个什么样的,进入取款机,然后锁门,然后插卡进行取钱。如下图:
假设此时小万进去取钱,但出现了一个情况:ATM机里没钱,就导致了小万无法取钱,她只好开门出去,但她里面又进去了,想着过了一分钟了,应该有钱了吧,但没有,又出去,然后又进来,如此反复,就会导致其他人无法进去存钱取钱,而小万也无法进行取钱操作。
这放到我们线程之中就是,一个线程t1对一个对象进行加锁后,又解锁,然后立马又进行加锁,然后又解锁,如此反复,其中t1并没有实质性的释放锁,这就会导致t1线程陷入忙等,而其他线程一直获取不到锁,一直处于阻塞等待的状态。这就会导致一个极端的情况:线程饿死。
线程饿死:它指的是一个或多个线程由于某种原因无法获取所需的资源或执行机会,导致它们无法继续正常执行,从而被阻塞在某个状态,不能完成其任务。这种情况通常是由于资源竞争或优先级设置不当导致的。
此时使用wait()和notify()就能很好的解决上述问题,当小万发现ATM机里没钱后就wait,wait就会释放锁,并阻塞等待。而当路人甲乙丙中的一个人获取到锁并进行存钱操作后就会notify唤醒小万,此时问题就得到解决了。
2. wait()方法
wait()方法要做的事就是让某个线程进行等待(阻塞等待),等待另一个线程完成某个任务或者达到某个状态后唤醒该线程。
【注意】 wait()和notify()是Object的方法,所以只要是个类对象,不是内置类型(也叫基本数据类型),都可以使用wait()和notify()方法
wait()具体做的事:
- 让当前线程阻塞等待(将该线程放到等待队列中)
- 释放当前的锁
- 满足一定条件被唤醒,继续尝试获取该锁
wait()结束等待要做的事:
- 其他线程调用该对象的 notify 方法.
- wait 等待时间超时 (wait 方法提供一个带有 timeout 参数的版本, 来指定等待时间).
- 其他线程调用该等待线程的 interrupted 方法, 导致 wait 抛出 InterruptedException 异常.
这就表示满足上述任意条件,调用wait()的线程就会被唤醒。
使用wait()的注意事项:
- 使用wait()需要搭配着synchronized使用,这其实也不难理解,当我们在某个线程中调用wait()方法时,就意味着需要释放该线程的锁了,那如果我们没进行加锁又何来解锁一说。
这里我们可以看看具体没进行synchronized加锁的代码例子:
public class Demo {