持续学习&持续更新中…

守破离


【Java从零到架构师第1季】【并发 Concurrent 03】线程间通信_ReentrantLock_线程池

  • 线程间通信
  • 线程间通信—示例
  • 可重入锁ReentrantLock
  • ReentrantLock的使用
  • 线程池
  • 线程池—基本使用
  • 参考

线程间通信

  1. 调用wait、notify、notifyAll方法的obj对象必须是同一个
  2. 调用wait、notify、notifyAll方法的线程必须拥有该obj对象的内部锁

线程间通信—示例

注意:

  • 消费者线程和生产者线程中调用obj.wait、obj.notify、obj.notifyAll方法时,使用的obj必须是同一个对象。

  • 消费者线程和生产者线程必须持有obj的内部锁(监视锁),才能成功调用wait、notify、notifyAll方法,否则会出现异常。

代码:

Producer:

public class Producer implements Runnable{private Drop drop;public Producer(Drop drop) {this.drop = drop;}@Overridepublic void run() {String[] foods = {"beef", "bread", "apple", "cookie", "banana"};for (String food : foods) {try {Thread.sleep(1500);} catch (InterruptedException e) {}drop.add(food);}drop.add(null);}
}

Consumer:

public class Consumer implements Runnable {private Drop drop;public Consumer(Drop drop) {this.drop = drop;}@Overridepublic void run() {String food;while ((food = drop.get()) != null) {//            try {//                Thread.sleep(1500);
//            } catch (InterruptedException e) {}System.out.println("消费了:" + food);}}
}

Drop:

version1:

public class Drop {private String food;// isEmpty:true:消费者需要等待生产者// isEmpty:false:生产者需要等待消费者private boolean isEmpty = true;public synchronized void add(String food) {if(isEmpty) { // 如果没有foodthis.food = food; // 直接生产foodisEmpty = false; // 生产了food之后,就不为空了notifyAll(); // 生产好food后,就可以通知消费者线程消费food了}else { // 如果food还有,还没有被消费者消费完毕try { // 等待消费者消费完毕foodwait();} catch (InterruptedException e) {}this.food = food; // 消费者消费完food后,就可以生产food了isEmpty = false; // 生产了food之后,就不为空了notifyAll(); // 就可以通知消费者线程消费food了}}public synchronized String get() {if(isEmpty) { // 如果此时没有food,也就是生产者线程还没有生产完毕foodtry { // 等待生产者生产foodwait();} catch (InterruptedException e) {}} // 当生产者生产好了food之后,就可以消费food了// 此时有food可以消费isEmpty = true; // 消费了food,那么就应该为空了notifyAll(); // 通知生产者线程,我已经消费了food,你可以继续生产food了return food;}
}

老师课件上写的while(empty)是为了防止wait时出现异常(如果wait时出现了异常并且不做任何处理的话,那么程序就会按顺序执行下去,那样的话程序就会出现bug;因此使用while循环:如果wait时出现了异常还会继续wait)

在wait时应该使用while循环来防止wait失败(如果wait出现异常,还得继续wait)

version2(使用while循环代替if循环):

public class Drop {private String food;// isEmpty:true:消费者需要等待生产者// isEmpty:false:生产者需要等待消费者private boolean isEmpty = true;// 使用while循环代替if循环、使用while循环执行wait方法的目的是:// 当wait时出现异常,还会继续wait,而不是执行之后的代码public synchronized void add(String food) {if(isEmpty) { // 如果没有foodthis.food = food; // 直接生产foodisEmpty = false; // 生产了food之后,就不为空了notifyAll(); // 生产好food后,就可以通知消费者线程消费food了}else { // 如果food还有,还没有被消费者消费完毕while(!isEmpty) {try { // 等待消费者消费完毕foodwait();} catch (InterruptedException e) {}}this.food = food; // 消费者消费完food后,就可以生产food了isEmpty = false; // 生产了food之后,就不为空了notifyAll(); // 就可以通知消费者线程消费food了}}public synchronized String get() {while(isEmpty) { // 如果此时没有food,也就是生产者线程还没有生产完毕foodtry { // 等待生产者生产foodwait();} catch (InterruptedException e) {}} // 当生产者生产好了food之后,就可以消费food了// 此时有food可以消费isEmpty = true; // 消费了food,那么就应该为空了notifyAll(); // 通知生产者线程,我已经消费了food,你可以继续生产food了return food;}
}

测试:

    public static void main(String[] args) {/*1.调用wait、notify、notifyAll方法的obj对象必须是同一个2.调用wait、notify、notifyAll方法的线程必须拥有该obj对象的内部锁*/Drop drop = new Drop();Consumer consumer = new Consumer(drop);Producer producer = new Producer(drop);new Thread(consumer).start();new Thread(producer).start();}

可重入锁ReentrantLock

    public static void main(String[] args) {// 可重入锁,有些地方叫做递归锁// synchronized是可重入的synchronized ("1") {synchronized ("1") {System.out.println("1");}}}

我们可以认为:每一个线程都有属于自己的锁持有计数器

ReentrantLock的使用

public class Station implements Runnable {private final ReentrantLock lock = new ReentrantLock();private int tickets = 100;public boolean saleTicket() {try{lock.lock();if (tickets < 1) return false;tickets--;System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + tickets + "张票。");return tickets > 0;}finally {lock.unlock();}}@Overridepublic void run() {while (saleTicket()) ;}
}

线程池

线程池—基本使用

    public static void main(String[] args) {final ExecutorService pool = Executors.newFixedThreadPool(5);for (int i = 1; i <= 10; i++) {pool.execute(() -> {System.out.println(Thread.currentThread().getName());});}pool.shutdown();}

参考

小码哥-李明杰: Java从0到架构师①零基础高效率入门.


本文完,感谢您的关注支持!


【Java从零到架构师第1季】【并发 Concurrent 03】线程间通信_ReentrantLock_线程池相关推荐

  1. 【Java从零到架构师第③季】【49】会话管理—Token_ehcache

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][49]会话管理-Token_ehcache 基于Cookie.Session 基于Token ehcache 简单使用 项目使用 ...

  2. 【Java从零到架构师第③季】【48】SpringBoot-Swagger

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][48]SpringBoot-Swagger 接口文档-Swagger 基本使用 不使用starter 使用starter(Swa ...

  3. 【Java从零到架构师第③季】【26】SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][26]SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的 利用反射获取方法的参数名 直接编译 修 ...

  4. 【Java从零到架构师第③季】【24】SpringMVC-概述_入门

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][24]SpringMVC-概述_入门 Spring.SpringMVC.MyBatis之间的关系 SpringMVC简介 Spr ...

  5. 【Java从零到架构师第③季】【28】SpringMVC-Servlet的URL匹配_path-matching suffix-pattern

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][28]SpringMVC-Servlet的URL匹配_path-matching suffix-pattern Servlet的 ...

  6. 【Java从零到架构师第二季】【07】JDBC FOR MySQL

    持续学习&持续更新中- 学习态度:守破离 JDBC FOR MySQL 什么是JDBC 如何通过Java操作数据库 JDBC是属于JavaSE的一部分 下载MySQL的JDBC实现 JDBC细 ...

  7. 【Java从零到架构师第二季】【14】AJAX

    持续学习&持续更新中- 学习态度:守破离 AJAX 同步请求和异步请求 未学AJAX之前向服务器提交请求的方式 同步和异步 AJAX 什么是AJAX AJAX的常见使用方式 原生 jQuery ...

  8. java线程间通信_java线程间通信:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...

  9. java线程通信概念_java基础线程总结(线程概念、线程创建方式、线程间通信、线程重要方法)...

    基础篇之<线程> @author :kern ---------------------------------------------------------------- 一:进程:是 ...

最新文章

  1. 《树莓派Python编程指南》——2.2 一个Python游戏:猫和老鼠
  2. 敏捷和DevOps:是敌是友?
  3. python面试常见问题-Python面试中最常见的25个问题
  4. 使用Strust2框架写HelloWorld
  5. BuildIt: Visual Studio .NET 的自动生成工具
  6. IDEA2021创建Java Web项目
  7. 备战双 11!蚂蚁金服万级规模 K8s 集群管理系统如何设计?
  8. 最可怕的企业“内卷化”,是走入以下10个误区而不自知
  9. AI(2)---机器学习产品交互设计原则
  10. Ubuntu14.04安装中文输入法以及解决Gedit中文乱码问题
  11. 语音识别结合应用场景之后
  12. $(document).ready
  13. Mysql 可重复读
  14. 2020法研杯比赛阅读理解任务冠军参赛总结
  15. 怎样在Windows 2016 Hyper-V上创建虚拟机
  16. 打开struts-config.xml 报错 解决方法Could not open the editor
  17. Element UI 官网以及其他技术文档
  18. mysql身份证唯一查询_Mysql查询SQL相关总结(根据生日以及身份证查询年龄以及性别区域等)...
  19. win10卸载预装软件
  20. hadoop快速自我学习--hadoop平台管理与维护

热门文章

  1. 综合案例(09-小兔鲜项目)
  2. int类型的最大值和最小值
  3. 【BZOJ4883】棋盘上的守卫
  4. android广播机制初步学习——短信黑名单
  5. Unity编辑器插件 ——等比例重新设置图片size
  6. Servlet 生命周期概述
  7. 每日一记:windows官方桌面显示自定义文字软件BGInfo
  8. mysql 双冒号_沙河壹佰
  9. win7使用VMware安装win7虚拟机上网设置
  10. Linux-2.6.20的LCD驱动分析(二)