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

设计建设网站公司网站seo实战培训班

设计建设网站公司网站,seo实战培训班,微信扫一扫登录网站如何做,北海网站建设公司1、为什么需要线程的等待和唤醒 线程的等待唤醒机制是一种经典的“生产者和消费者”模型。例如食品加工厂,食品加工人员和原料补给人员,在有充足原料时,补给人员是在等待,等到原料不够时,食品加工人员通知补给人员&am…

1、为什么需要线程的等待和唤醒

线程的等待唤醒机制是一种经典的“生产者和消费者”模型。例如食品加工厂,食品加工人员和原料补给人员,在有充足原料时,补给人员是在等待,等到原料不够时,食品加工人员通知补给人员(唤醒)。在我们开发诸如此类需求的时候两个线程之间协调等待和唤醒还是很有必要的。那咱们看看都有那些方式实现线程等待和唤醒机制。

2、线程等待和唤醒机制方式 

实现线程等待和唤醒机制主要有3中方式分别是:

  • 使用 Object 中的 wait() 方法让线程等待,使用 Object 中的 notify() 方法唤醒线程
  • 使用 JUC 包中 Condition 的 await() 方法让线程等待,使用 signal() 方法唤醒线程
  • 使用LockSupport类的park()方法让线程等待,使用unpark()方法唤醒线程。 

 那这三种方式具体怎么使用,都有那些优缺点呢?我们通过实例代码演示。

3、线程等待和唤醒机制实例

3.1、使用 Object 中的 wait() 方法让线程等待,使用 Object 中的 notify() 方法唤醒线程

代码:

package com.lc.test02;import java.util.concurrent.TimeUnit;/*** @author liuchao* @date 2023/4/8*/
public class ThreadWaitOne {/*** 注意:必须使用同一把锁*/static Object lock = new Object();public static void main(String[] args) {/*** 线程1*/Thread t1 = new Thread(() -> {synchronized (lock) {System.out.println("进入" + Thread.currentThread().getName());try {lock.wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println(Thread.currentThread().getName() + "被唤醒");}}, "t1");t1.start();try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();}/*** 线程2*/Thread t2 = new Thread(() -> {synchronized (lock) {System.out.println("进入" + Thread.currentThread().getName());lock.notify();System.out.println("唤醒通知已发");}}, "t2");t2.start();}
}

效果:

进入t1
进入t2
唤醒通知已发
t1被唤醒 

总结:此种方式必须使用同一把锁并且必须包含在synchronized代码块中,如果未使用synchronized包裹,则会报错。

Exception in thread "t1" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Object.java:502)
    at com.lc.test02.ThreadWaitOne.lambda$main$0(ThreadWaitOne.java:24)
    at java.lang.Thread.run(Thread.java:750)

并且wait方法的调用必须要在notify/notifyAll的调用之前,否则线程将永远不会被唤醒。 

3.2、使用 JUC 包中 Condition 的 await() 方法让线程等待,使用 signal() 方法唤醒线程

代码:

package com.lc.test02;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** @author liuchao* @date 2023/4/8*/
public class ThreadWaitTwo {/*** 必须是同一把锁*/static Lock lock = new ReentrantLock();static Condition condition = lock.newCondition();public static void main(String[] args) {/*** 线程1*/Thread t1 = new Thread(() -> {lock.lock();try {System.out.println("进入" + Thread.currentThread().getName());condition.await();} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {lock.unlock();}System.out.println(Thread.currentThread().getName() + "被唤醒");}, "t1");t1.start();try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();}/*** 线程2*/Thread t2 = new Thread(() -> {lock.lock();try {System.out.println("进入" + Thread.currentThread().getName());condition.signal();System.out.println("唤醒通知已发");} finally {lock.unlock();}}, "t2");t2.start();}
}

效果:

进入t1
进入t2
唤醒通知已发
t1被唤醒 

总结:使用此中方式必须配合lock,代码必须被lock包裹,否则将报错

Exception in thread "t1" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036)
    at com.lc.test02.ThreadWaitTwo.lambda$main$0(ThreadWaitTwo.java:28)
    at java.lang.Thread.run(Thread.java:750) 

 并且await方法的调用必须在signal/signalAll方法调用之前,否则t1也是不会被唤醒

3.3、使用LockSupport类的park()方法让线程等待,使用unpark()方法唤醒线程。  

LockSupport 类使用了一种名为 Permit (许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit 只有两个值 1 和 0,默认是 0

  • 阻塞

        ①、park()/park(Object blocker)
        ②、permit 默认是 0,所以一开始调用 park() 方法,当前线程就会阻塞,直到别的线程将当前线程的 permit 设置为 1 时,park 方法会被唤醒,然后会将 permit 再次设置为 0 并返回。
        ③、阻塞当前线程/阻塞传入的具体线程

  • 唤醒

        ①、unpark(Thread thread)
        ②、调用 unpark(Thread thread) 方法后,就会将 thread 线程的许可 permit 设置为 1(注意多次调用 unpark 方法,不会累加,permit 值还是 1)会自动唤醒 thread 线程,即之前阻塞中的 LockSupport.park()方法会立即返回
        ③、唤醒处于阻塞状态的指定线程

代码:

package com.lc.test02;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;/*** @author liuchao* @date 2023/4/8*/
public class ThreadWaitThree {public static void main(String[] args) {/*** 线程1*/Thread t1 = new Thread(() -> {System.out.println("进入" + Thread.currentThread().getName());LockSupport.park();System.out.println(Thread.currentThread().getName() + "被唤醒");}, "t1");t1.start();try {TimeUnit.MILLISECONDS.sleep(200);} catch (InterruptedException e) {Thread.currentThread().interrupt();}/*** 线程2*/Thread t2 = new Thread(() -> {System.out.println("进入" + Thread.currentThread().getName());LockSupport.unpark(t1);System.out.println("唤醒通知已发");}, "t2");t2.start();}
}

效果:

进入t1
进入t2
唤醒通知已发
t1被唤醒 

结论:此种方式不需要增加同步机制,天生就是无锁机制实现线程等待和唤醒,并且因为是通过许可方式来唤醒线程的,所以许可是在等待(调用park()方法)前还是后是不影响的(park和unpark调用先后顺序我关),此种方式也是我们推荐使用的方式。当然,这种方式也是有缺点的,许可最多只有一个,如果等待多次(调用多次park()方法),线程也就永远不能唤醒了。

演示线程的唤醒和unpark先调用还是后调用无关:

package com.lc.test02;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;/*** @author liuchao* @date 2023/4/8*/
public class ThreadWaitThree {public static void main(String[] args) {/*** 线程1*/Thread t1 = new Thread(() -> {try {//等待300毫秒,让t2先执行TimeUnit.MILLISECONDS.sleep(300);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("进入" + Thread.currentThread().getName());LockSupport.park();System.out.println(Thread.currentThread().getName() + "被唤醒");}, "t1");t1.start();/*** 线程2*/Thread t2 = new Thread(() -> {System.out.println("进入" + Thread.currentThread().getName());LockSupport.unpark(t1);System.out.println("唤醒通知已发");}, "t2");t2.start();}
}

效果:

进入t2
唤醒通知已发
进入t1
t1被唤醒 

演示多次调用unpark+多次调用park导致线程不能被唤醒:

package com.lc.test02;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;/*** @author liuchao* @date 2023/4/8*/
public class ThreadWaitThree {public static void main(String[] args) {/*** 线程1*/Thread t1 = new Thread(() -> {System.out.println("进入" + Thread.currentThread().getName());/*** 调用两次park方法*/LockSupport.park();LockSupport.park();System.out.println(Thread.currentThread().getName() + "被唤醒");}, "t1");t1.start();try {//等待300毫秒,让t2先执行TimeUnit.MILLISECONDS.sleep(300);} catch (InterruptedException e) {Thread.currentThread().interrupt();}/*** 线程2*/Thread t2 = new Thread(() -> {System.out.println("进入" + Thread.currentThread().getName());/*** 调用了两次park我们调用三次unpark 还是无法唤醒t1线程的*/LockSupport.unpark(t1);LockSupport.unpark(t1);LockSupport.unpark(t1);System.out.println("唤醒通知已发");}, "t2");t2.start();}
}

 

http://www.khdw.cn/news/4922.html

相关文章:

  • 爱用建站正规吗搜索引擎推广文案
  • phpcms电影网站开发南宁seo外包要求
  • 有没有教给做宝宝衣服的网站大连网站建设
  • 网站可信认证在哪里做短视频推广平台
  • 海外代购正品网站推广图片大全
  • 企业自建b2b电子商务网站有哪些优化排名软件
  • dede网站301怎么做网站优化
  • 东莞网站建设纸品包装搜索引擎营销方法主要有三种
  • 做网站需要学习多久网页制作学习
  • wordpress图片编辑插件下载搜索引擎优化的五个方面
  • 全国做网站的大公司国家再就业免费培训网
  • 专做批发的网站有哪些沈阳seo整站优化
  • 临沂做商城网站建设抖音引流推广免费软件app
  • 政府门户网站建设对策建议广州网站开发多少钱
  • 网站手机客户端制作自助优化排名工具
  • asp网站发邮件太原关键词优化公司
  • 各种大型网站岳阳seo公司
  • 青岛市建设监理网站网络服务费计入什么科目
  • 做网站好的书国内营销推广渠道
  • 青岛硅谷网站建设sem推广和seo的区别
  • 网站建设工作稳定吗域名查询注册商
  • 医院网站建设费用惠州企业网站seo
  • 建外做网站的公司近期舆情热点事件
  • 硬盘做网站空间今日十大新闻
  • 长安仿做网站外贸网站建设推广
  • 众美商务公馆做网站百度网页版 入口
  • 官方网站下载拼多多阿里指数查询官网
  • 腾云网站建设优化 英语
  • 网站设计基础语言不包括这些内容上海牛巨微seo关键词优化
  • 深圳手机集团网站建设seo常用工具