云博客
  • 前端
  • windos
  • 微信
  • 数据库
  • 移动开发
  • 技术杂谈
  • 评论

Android-Java多线程通讯(生产者 消费者)&10条线程对-等待唤醒/机制的管理

# 移动开发 2024-05-05 14:17 0 30 来源: 云博客

上一篇博客 Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 是两条线程(Thread-0 / Thread-1) 在被CPU随机切换执行;

 

而今天这篇博客是,在上一篇博客Android-Java多线程通讯(生产者 消费者)&等待唤醒机制 的基础上,扩大规模增加10条线程去执行 生产者 消费者;

 

注意:?? 上一篇博客是两条线程在执行(生产者 消费者)例如:当Thread-0 锁.wait(); 等待 冻结后,  Thread-1 锁.notify(); 唤醒的一定是 Thread-0(因为Thread-1 锁.notify(); 后

会在线程池里面 根据同步锁??找到冻结wait();的线程,而在共享的同步锁??中只有Thread-0),所以根据同步锁 就找到了 Thread-0;  唤醒成功。

 

所以根据以上分析,所以两条线程去执行生产者 消费者 是没有问题的:

案例一(两条线程去执行生产者 消费者);

package android.java.thread16;/** * 描述资源 */class Res { /** * name 是共享数据,被Thread-0 Thread-1公用使用 */ private String name; /** * id 是共享数据,被Thread-0 Thread-1公用使用 */ private int id; /** * flag 是共享数据,被Thread-0 Thread-1公用使用 */ private boolean flag; // 定义标记 默认第一次为false /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void put(String name) { /** * 生产之前判断标记 */ if (!flag) { // 开始生产 id += 1; this.name = name + " 商品编号:" + id; System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.name); // 生产完毕 /** * 修改标记 */ flag = true; /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ notify(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void out() { /** * 消费之前判断标记 */ if (flag) { // 开始消费 System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name); // 消费完毕 /** * 修改标记 */ flag = false; /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ notify(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } }}/** * 描述生产者任务 */class ProduceRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ProduceRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { for (int i = 0; i < 20; i++) { res.put("面包??"); } }}/** * 描述消费者任务 */class ConsumeRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ConsumeRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { for (int i = 0; i < 20; i++) { res.out(); } }}/** * 多线程通讯案例 */public class ThreadCommunicationDemo { public static void main(String[] args) { // 创建资源对象 Res res = new Res(); // 创建生产者任务 ProduceRunnable produceRunnable = new ProduceRunnable(res); // 创建消费者任务 ConsumeRunnable consumeRunnable = new ConsumeRunnable(res); // 启动生产者任务 new Thread(produceRunnable).start(); // 启动消费者任务 new Thread(consumeRunnable).start(); }}

执行结果,和谐了 生产一个 消费一个:

技术分享图片

 

 


 

 

以上案例一,由于只有两条线程去执行生产者 消费者,所以 锁.notify(); 唤醒的线程只有一个,所以 以上案例一是没有问题的;

案例二:以下就使用10条线程去 执行生产者 消费者,会出现 锁.notify(); 把自身线程唤醒,出现混乱错误??

package android.java.thread18;/** * 描述资源 */class Res { /** * name 是共享数据,被Thread-0 Thread-1公用使用 */ private String name; /** * id 是共享数据,被Thread-0 Thread-1公用使用 */ private int id; /** * flag 是共享数据,被Thread-0 Thread-1公用使用 */ private boolean flag; // 定义标记 默认第一次为false /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void put(String name) { /** * 生产之前判断标记 */ if (!flag) { /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } // 开始生产 id += 1; this.name = name + " 商品编号:" + id; System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.name); // 生产完毕 /** * 修改标记 */ flag = false; /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ notify(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void out() { /** * 消费之前判断标记 */ if (flag) { /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } // 开始消费 System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name); // 消费完毕 /** * 修改标记 */ flag = true; /** * 唤醒 wait(); 冻结的线程,如果没有就是空唤醒,Java是支持的 */ notify(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 }}/** * 描述生产者任务 */class ProduceRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ProduceRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { while(true) { res.put("面包??"); } }}/** * 描述消费者任务 */class ConsumeRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ConsumeRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { while (true) { res.out(); } }}/** * 多线程通讯案例 -->>> 10条线程对 多生产 多消费 对等待/唤醒的管理控制 */public class ThreadCommunicationDemo { public static void main(String[] args) { // 创建资源对象 Res res = new Res(); // 创建生产者任务 ProduceRunnable produceRunnable = new ProduceRunnable(res); // 创建消费者任务 ConsumeRunnable consumeRunnable = new ConsumeRunnable(res); // 启动生产者任务 new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); // 启动消费者任务 new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); }}

执行结果:

出现异常的原因:

由于有10个线程在执行 生产者 消费者,就会造成 notify();混乱 例如:生产者 生产完毕后 Thread-5>>>wait(); Thread-5>>>notify(); 的时候有可能会把自身线程Thread-5唤醒;
由于有10个线程在执行 生产者 消费者,就会造成 notify();混乱 例如:消费者 消费完毕后 Thread-8>>>wait(); Thread-8>>>notify(); 的时候有可能会把自身线程Thread-8唤醒;

当把自身线程Thread-*唤醒的时候,就已经是?错误的,异常的程序了;

技术分享图片

 

 


 

 

案例三,主要是解决以上案例二的问题:

【修改点1:把if 修改成 while】
【修改点2:修改成notifyAll】

 

package android.java.thread18;/** * 描述资源 */class Res { /** * name 是共享数据,被Thread-0 Thread-1公用使用 */ private String name; /** * id 是共享数据,被Thread-0 Thread-1公用使用 */ private int id; /** * flag 是共享数据,被Thread-0 Thread-1公用使用 */ private boolean flag; // 定义标记 默认第一次为false /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void put(String name) { /** * 生产之前判断标记,【修改点1:把if 修改成 while】 */ while (!flag) { /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } // 开始生产 id += 1; this.name = name + " 商品编号:" + id; System.out.println(Thread.currentThread().getName() + "生产者 生产了:" + this.name); // 生产完毕 /** * 修改标记 */ flag = false; /** * 唤醒所有 【修改点2:修改成notifyAll】 */ notifyAll(); // 注意:?? wait(); notify(); notifyAll 这些必须要有同步锁包裹着 } /** * 对操作共享数据的地方加入同步锁的方式来解决安全问题 * public synchronized(this) void put(String name) { */ public synchronized void out() { /** * 消费之前判断标记,【修改点1:把if 修改成 while】 */ while (flag) { /** * 当前自己线程 冻结,释放CPU执行资格,释放CPU执行权,CPU就会去执行其他线程了 */ try { wait(); // 注意:?? wait(); notify(); 这些必须要有同步锁包裹着 } catch (InterruptedException e) { e.printStackTrace(); } } // 开始消费 System.out.println(Thread.currentThread().getName() + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 消费者 消费了:" + this.name); // 消费完毕 /** * 修改标记 */ flag = true; /** * 唤醒所有 【修改点2:修改成notifyAll】 */ notifyAll(); // 注意:?? wait(); notify(); notifyAll 这些必须要有同步锁包裹着 }}/** * 描述生产者任务 */class ProduceRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ProduceRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { while(true) { res.put("面包??"); } }}/** * 描述消费者任务 */class ConsumeRunnable implements Runnable { /** * 此变量已经不是共享数据了,因为: * new Thread(produceRunnable).start(); * new Thread(consumeRunnable).start(); * * 所以:Thread-0有自己的res Thread-1也有自己的res */ private Res res; ConsumeRunnable(Res res) { this.res = res; } /** * 执行线程任务 */ @Override public void run() { while (true) { res.out(); } }}/** * 多线程通讯案例 -->>> 10条线程对 多生产 多消费 对等待/唤醒的管理控制 */public class ThreadCommunicationDemo { public static void main(String[] args) { // 创建资源对象 Res res = new Res(); // 创建生产者任务 ProduceRunnable produceRunnable = new ProduceRunnable(res); // 创建消费者任务 ConsumeRunnable consumeRunnable = new ConsumeRunnable(res); // 启动生产者任务 new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); new Thread(produceRunnable).start(); // 启动消费者任务 new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); new Thread(consumeRunnable).start(); }}

执行结果:10条线程对-等待唤醒/机制的管理 比较OK??

 技术分享图片

 

1.修改出现问题的代码:由于每次锁.wait(); 之前是使用if判断,if判断会引发 "if (flag) {此时CPU就在这里临时阻塞了,当再次获得CPU执行权时 就属于异常了}"   所以修改每次锁.wait(); 之前判断 使用循环while(flag){} while会往回循环判断,就可以解决此问题了;

2.修改出现问题的代码:锁.notify();后 会唤醒同步锁??里面冻结的任意一个线程,有可能唤醒自身线程,有可能唤醒其他线程,现在由于加了while(flag){}来判断,唤醒自身线程会拦截了,不用担心自身线程被唤醒了,就算唤醒自身线程也会拦截;        现在愁的是(锁.notify(); 如果唤醒自身线程,就无法唤醒其他线程了)  所以解决方案是:全部唤醒 notifyAll(); 反正已经修改了while(falg){} 判断标记拦截方式了

 

 

notify();   notifyAll();    wait();   必须在 synchronized{里面使用,因为 这些方法需要 同步锁}

 

 
0

相关文章

axios post后台接收不到参数
axios post后台接收不到参数
解决krpano全景视频在QQ浏览器、安卓不能正常播放的问题
解决krpano全景视频在QQ浏览器、安卓不能正常播放的问题
移动端:Flex弹性盒布局
移动端:Flex弹性盒布局
Android屏幕适配框架-(今日头条终极适配方案)
Android屏幕适配框架-(今日头条终极适配方案)
移动端:项目实战
移动端:项目实战
Android Studio – No cached version available for offline mode
Android Studio – No cached version available for offline mode
云博小周宇
云博小周宇 投稿者
  • 96804 篇文章
  • 0 条评论
最近文章
  • 数据格式转换 (三)Office文档转HTML
  • 【转】Node.js到底是用来做什么的
  • 20164317《网络对抗技术》Exp9 Web安全基础
  • linux web站点常用压力测试工具httperf
  • JSOI2016 最佳团体
  • Node.js 事件触发器详细总结
  • 仿 MVC 三大特性
  • 如何搭建一个简易的Web框架
  • js 原型里面写方法
  • css里的BFC用法
  • html之input
  • Apache开启GZIP压缩功能方法
  • Node.js 命令行工具的编写
  • 前端性能优化成神之路-HTTP压缩开启gzip
  • How to use NetSuite SDF to download bundles/components
  • 前端 HTML文档 详解
  • webstorm 支持vue element-ui 语法高亮属性自动补全
  • 从零开始搭建服务器部署web项目
  • node.js密码加密实践
  • 四: 使用vue搭建网站前端页面
    前端windos微信数据库移动开发技术杂谈
    滇ICP备16006824号-3