当前位置: 首页 > news >正文

顺企网网站建设营销策划咨询

顺企网网站建设,营销策划咨询,开创网站要怎么做,怎样用php做网站目录 wait() 方法 notify() 方法 notifyAll() 方法 nofity 和 notifyAll wait 和 notify wait 和 sleep 的区别 wait 和 join 的区别 由于线程之间是抢占式执行的,因此,线程之间执行的先后顺序难以预知,但是,在实际开发中&…

目录

wait() 方法

notify() 方法

notifyAll() 方法

nofity 和 notifyAll

wait 和 notify

wait 和 sleep 的区别

wait 和 join 的区别


由于线程之间是抢占式执行的,因此,线程之间执行的先后顺序难以预知,但是,在实际开发中,有时候我们希望合理的协调多个线程之间的执行先后顺序

例如:

在篮球场上,每个队员都是独立的 执行流,也就是一个 线程

当需要完成一个具体的得分动作时,就需要多个队员相互配合,按照一定的顺序执行一定的动作,线程 1 先向 线程 2 "传球",线程2 才能 "扣篮"

要完成 协调工作,主要涉及到三个方法:

wait()/wait(long timeout):让当前线程进入等待状态

notify():唤醒当前对象上等待的线程

notifyAll():唤醒当前对象上所有等待的线程

接下来,我们就来学习这三个方法,我们首先来看 wait 方法 

wait() 方法

我们先来看一个例子:

一个柜子里有食物,5个人(线程)共同使用这个柜子,并从里面拿取食物(假设同一时间只能一人拿取),1号先使用这个柜子(对其进行加锁),但是当1号打开这个柜子时发现柜子里没有食物,此时1号就会关上柜门(释放锁),等有食物时再来拿

此时,其他人就会竞争这个锁,争取使用柜子,而刚刚释放锁的1号,也会参与到锁竞争中,因此,也就有可能刚刚释放锁的1号又重新拿到锁,并且,由于1号离得近(1号线程处于 RUNNABEL 状态,其他线程处于 BLOCKED 状态),他就有很大可能再次拿到锁

1号又拿到锁,发现没有食物,又释放锁,又竞争到锁,发现没有食物,又释放锁......

如此重复,就会导致1号反复获取到锁,但是又不能完成实质性的操作;而其他线程,则无法拿到锁。这种情况,称之为 线程饿死(线程饥饿)

线程饿死这样的情况,属于概率性事件(1号拿到锁的概率更大,但是其他线程也有可能会拿到锁),不像 死锁,一旦出现后,就一定会阻塞,但 线程饥饿 这样的情况,也极大可能会影响其他线程的运行

因此,我们就需要对这种情况进行处理:

线程饿死出现的关键在于:1号发现自己要执行逻辑的前提条件不具备(柜子中没有食物)时,就应该主动放弃对锁的竞争,主动放弃去 CPU 上调度执行,即,进入阻塞状态,一直等待前提条件具备了(其他线程往柜子中放了食物),此时再解除阻塞,参与到锁竞争中

此时,就可以使用 wait 进行等待:

让 1号 判断前提条件是否满足,若不满足,则 wait 等待

其他线程让条件满足后,再通过 notify 来唤醒 1号

接下来,我们就通过具体的代码来学习 wait 的使用:

 我们让 t1 线程进入等待:

public class ThreadDemo18 {public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() -> {System.out.println("t1 进入等待之前");// 进入等待try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}});t1.start();}
}

此时,观察运行结果,发现抛出了异常 IllegalMonitorStateException

为什么会抛出异常呢?

 这是因为 wait 必须搭配 synchronized 来使用

wait 做的事情有:

1. 使当前执行代码的线程进行等待(将线程放到等待队列中)

2. 释放当前锁

3. 满足一定条件时被唤醒,重新尝试获取到这个锁

wait 要对当前锁进行释放,释放锁的前提,是要先拿到锁,因此 wait 必须放到 synchronized 中使用

public class ThreadDemo18 {public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() -> {System.out.println("t1 进入等待之前");synchronized (locker) {// 进入等待try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}});t1.start();}
}

wait、sleep 和 join,都有可能被 interrupt 提前唤醒,都需要处理异常 

每个对象里都有一把锁,调用 wait 的对象,必须和 synchronized 中的锁对象是一致的,wait 解除的锁是 locker对象 的锁,后续 wait 被唤醒后,重新获取到锁,当然也是获取到 locker 对象的锁 

此时,t1 线程就在 wait 这里阻塞了:

我们使用 jconsole 来观察 t1 线程的状态:

此时,线程进入 WAITING 状态 

而 wait 结束等待的条件为:

1. 其他线程调用该对象的 notify 方法

2. wait 等待时间超时(wait 方法提供了带有 timeout 参数的版本,用来指定等待最长时间)

3. 其他线程调用该等待线程的 interrupt 方法,导致 wait 抛出 InterruptedException 异常

接下来,我们就来学习 notify() 方法,来唤醒等待中的线程

 

notify() 方法

notify() 方法用于唤醒等待的线程

我们在 t2 线程中唤醒 t1 线程:

public class ThreadDemo18 {public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() -> {System.out.println("t1 进入等待之前");synchronized (locker) {// 进入等待try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}});Thread t2 = new Thread(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}locker.notify();});t1.start();t2.start();}
}

此时抛出异常 IllegalMonitorStateException

 

这是因为 Java 中约定 notify 也需要放到 synchronized 中

public class ThreadDemo18 {public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() -> {System.out.println("t1 进入等待之前");synchronized (locker) {// 进入等待try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1 结束等待");});Thread t2 = new Thread(() -> {try {Thread.sleep(1000);synchronized (locker) {System.out.println("t2 notify 之前");locker.notify();System.out.println("t2 notify 之后");}} catch (InterruptedException e) {e.printStackTrace();}});t1.start();t2.start();}
}

 

在上述代码中:

t1 执行起来后就会立即尝试获取锁,拿到锁后,就立即打印 "t1 进入等待之前",并进入 wait 方法(释放锁且阻塞等待)

t2 执行起来后,会先 sleep(1000)(保证 t1 能够先拿到锁)

t2 sleep 之后,t1 处于 WAINTING 状态,且锁是释放了的,此时,t2 就会立即拿到锁

t2 打印 "t2 notify 之前",执行 notify,唤醒 t1(此时 t1 就从 WAITING 状态恢复回来)

但是由于 t2 还未释放锁,t1 WAITING 状态恢复后,会尝试获取锁,此时会处于阻塞 BLOCKED 状态(由于锁竞争引起的)

t2 执行完 "t2 notify 之后",就会释放锁,且 t2 执行完毕

此时 t1 的wait 就能够获取到锁,并继续执行,打印 "t1 结束等待"

由于,我们也可以知道:当前线程在执行 notify() 方法后,并不会立刻释放锁,而是等 synchronized 代码块执行完后,才会释放锁

如果有多个线程等待,则由线程调度器随机挑选一个处于 wait 状态的线程

 

notifyAll() 方法

notify() 方法只能唤醒其中一个等待的线程,而使用 notifyAll() 方法可以一次唤醒所有等待线程

public class ThreadDemo18 {public static void main(String[] args) {Object locker = new Object();Thread t1 = new Thread(() -> {System.out.println("t1 进入等待之前");synchronized (locker) {// 进入等待try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t1 结束等待");});Thread t2 = new Thread(() -> {try {Thread.sleep(1000);synchronized (locker) {System.out.println("t2 notify 之前");locker.notifyAll();System.out.println("t2 notify 之后");}} catch (InterruptedException e) {e.printStackTrace();}});Thread t3 = new Thread(() -> {System.out.println("t3 进入等待之前");synchronized (locker) {// 进入等待try {locker.wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("t3 结束等待");});t1.start();t2.start();t3.start();}
}

我们可以看到,notifyAll() 同时唤醒了 t1 和 t3 线程,但是,虽然同时唤醒了 2 个线程,但是这 2 个线程需要竞争锁,因此,并不是同时执行的,而是有先后顺序的执行

 

nofity 和 notifyAll

notify() 只会唤醒等待队列中的一个线程(由线程调度器随机挑选一个处于 wait 状态的线程),其他线程仍处于 wait 状态

notifyAll() 则会将等待队列中的线程全都唤醒,此时,这些线程需要重新竞争锁,谁先拿到锁,谁后拿到锁,也是不确定的

 

wait 和 notify

wait 和 notify/notifyAll 彼此之间是通过 object 对象联系起来的

若:

locker1.wait()

locker2.notify()

此时,是无法唤醒使用 locker1.wait() 的线程的,必须两个对象一致才能唤醒,调用 notify 使用的是哪个对象,就会唤醒哪个对象

 

wait 和 sleep 的区别

wait 和 sleep 都能够让线程放弃执行一段时间,但,wait 是用于线程之间的通信,而 sleep 则是让线程阻塞一段时间

wait  和 sleep 都可以被提前唤醒,wait 通过 notify 唤醒,sleep 通过 interrupt 唤醒,但是

使用 wait 时,一般都是在不确定要等多少时间的前提下使用的(超时时间是用来 "兜底" 的,防止出现 死等)

而使用 sleep 是需要知道需要等多少时间的前提下使用的,虽然能够提前唤醒,但通过异常进行唤醒,此时,大概率说明程序出现了一些特殊情况

此外,

wait() 需要搭配 synchronized 使用,但 sleep() 不需要

wait() 是 Object 提供的方法,sleep() 是 Thread 提供的静态方法

 

wait 和 join 的区别

同样的,wait 和 join 都能让线程放弃执行一段时间,等待其他线程先执行,但是,wait 是等到 notify 唤醒后,解除 wait 状态,然后参与到锁竞争中;而 join 需要等到其他线程执行完,才会继续执行

当一个线程调用 wait 方法时,会同步释放锁,然后该线程进入等待 状态,其他线程会竞争这把锁,得到锁的线程继续执行

而一个线程运行过程中调用 另一个线程的 join 方法时,当前线程就会停止执行,一直等到另一个线程执行完毕,才会继续执行

wait() 需要搭配 synchronized 使用,但 join() 不需要

wait() 是 Object 提供的方法,join() 是 Thread 提供的方法

http://www.hengruixuexiao.com/news/40957.html

相关文章:

  • bt磁力兔子引擎广州seo实战培训
  • 百度站长工具数据提交珠海网站建设制作
  • 富阳网站建设优化seo可以从以下几个方面进行
  • 西宁做网站制作的公司哪家好新媒体代运营
  • 小程序可视化开发工具厦门seo顾问
  • 和城乡建设厅官方网站网站关键词排名seo
  • 青岛专业建设网站sem模型
  • c2c网站架构常州网站建设书生商友
  • 西宁公安网站建设hyein seo官网
  • 最近中国新闻事件seo外链网
  • 网址导航类网站如何做推广品牌宣传策划公司
  • 免费学校网站系统抖音代运营
  • 网站设计就业前景如何如何搭建自己的网站
  • 网站组织管理建设甲马营seo网站优化的
  • 做外贸无法登录国外网站怎么办怎么在网上推销产品
  • wordpress 建视频网站国外推广网站
  • 如何在外管局网站做延期如何建立个人网址
  • wordpress模板和主题长沙优化网站推广
  • 做网站需要几大模板完善的seo网站
  • 网站网页怎么做河北企业网站建设
  • 主页免费下载长春seo公司哪家好
  • 网站建设定金合同范本免费视频外链生成推荐
  • wordpress多站点管理天天seo站长工具
  • 做网站首选九零后网络网络广告的概念
  • 婚纱网站页面设计seo网络优化专员是什么意思
  • 南京电子商务网站开发公司网络培训心得体会总结
  • 下沙做网站的公司网站开发详细流程
  • 西安建筑公司网站建设网页设计首页制作
  • 凡科做网站多少钱建设网站的十个步骤
  • 网站建设 关于我们接外贸订单的渠道平台哪个好