Java并发(十二)----线程应用之多线程解决烧水泡茶问题

news2024/12/27 13:07:55

1、背景

统筹方法,是一种安排工作进程的数学方法。它的实用范围极广泛,在企业管理和基本建设中,以及关系复杂的科研项目的组织与管理中,都可以应用。

怎样应用呢?主要是把工序安排好。

比如,想泡壶茶喝。当时的情况是:开水没有;水壶要洗,茶壶、茶杯要洗;火已生了,茶叶也有了。怎么办?

  • 办法甲:洗好水壶,灌上凉水,放在火上;在等待水开的时间里,洗茶壶、洗茶杯、拿茶叶;等水开了,泡茶喝。

  • 办法乙:先做好一些准备工作,洗水壶,洗茶壶茶杯,拿茶叶;一切就绪,灌水烧水;坐待水开了,泡茶喝。

  • 办法丙:洗净水壶,灌上凉水,放在火上,坐待水开;水开了之后,急急忙忙找茶叶,洗茶壶茶杯,泡茶喝。

哪一种办法省时间?我们能一眼看出,第一种办法好,后两种办法效率较低。

水壶不洗,不能烧开水,因而洗水壶是烧开水的前提。没开水、没茶叶、不洗茶壶茶杯,就不能泡茶,因而这些又是泡茶的前提。它们的相互关系,可以用下边的箭头图来表示:

从这个图上可以一眼看出,办法甲总共要16分钟(而办法乙、丙需要20分钟)。如果要缩短工时、提高工作效率,应当主要抓烧开水这个环节,而不是抓拿茶叶等环节。同时,洗茶壶茶杯、拿茶叶总共不过4分钟,大可利用“等水开”的时间来做。

洗茶壶,洗茶杯,拿茶叶,或先或后,关系不大,而且同是一个人的活儿,因而可以合并成为:

2、思路

参考上图,用两个线程(两个人协作)模拟烧水泡茶过程

文中办法乙、丙都相当于任务串行

而图一相当于启动了 4 个线程,有点浪费

用 sleep(n) 模拟洗茶壶、洗水壶等耗费的时间

3、解法1:join

@Slf4j(topic = "c.Test16")
public class Test16 {
​
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            log.debug("洗水壶");
            // TimeUnit.SECONDS.sleep(i); 
            sleep(1);  // sleep 1s  可使用上方的代码睡眠
            log.debug("烧开水");
            sleep(5); // sleep 5s
        },"老王");
​
        Thread t2 = new Thread(() -> {
            log.debug("洗茶壶");
            sleep(1); // sleep 1s
            log.debug("洗茶杯");
            sleep(2); // sleep 2s
            log.debug("拿茶叶");
            sleep(1); // sleep 1s
            try {
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("泡茶");
        },"小王");
​
        t1.start();
        t2.start();
    }
}

输出

解法1 的缺陷:

  • 上面模拟的是小王等老王的水烧开了,小王泡茶,如果反过来要实现老王等小王的茶叶拿来了,老王泡茶呢?代码最好能适应两种情况

  • 上面的两个线程其实是各执行各的,如果要模拟老王把水壶交给小王泡茶,或模拟小王把茶叶交给老王泡茶呢

4、解法2:wait/notify

class S2 {
    static String kettle = "冷水";
    static String tea = null;
    static final Object lock = new Object();
    static boolean maked = false;
​
    public static void makeTea() {
        new Thread(() -> {
            log.debug("洗水壶");
            sleep(1);
            log.debug("烧开水");
            sleep(5);
            synchronized (lock) {
                kettle = "开水";
                lock.notifyAll();
                while (tea == null) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (!maked) {
                    log.debug("拿({})泡({})", kettle, tea);
                    maked = true;
                }
            }
        }, "老王").start();
​
        new Thread(() -> {
            log.debug("洗茶壶");
            sleep(1);
            log.debug("洗茶杯");
            sleep(2);
            log.debug("拿茶叶");
            sleep(1);
            synchronized (lock) {
                tea = "花茶";
                lock.notifyAll();
                while (kettle.equals("冷水")) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (!maked) {
                    log.debug("拿({})泡({})", kettle, tea);
                    maked = true;
                }
            }
        }, "小王").start();
    }
}

输出

20:04:48.179 c.S2 [小王] - 洗茶壶
20:04:48.179 c.S2 [老王] - 洗水壶
20:04:49.185 c.S2 [老王] - 烧开水
20:04:49.185 c.S2 [小王] - 洗茶杯
20:04:51.185 c.S2 [小王] - 拿茶叶
20:04:54.185 c.S2 [老王] - 拿(开水)泡(花茶)

解法2 解决了解法1 的问题,不过老王和小王需要相互等待,不如他们只负责各自的任务,泡茶交给第三人来做

5、解法3:第三者协调

class S3 {
    static String kettle = "冷水";
    static String tea = null;
    static final Object lock = new Object();
​
    public static void makeTea() {
        new Thread(() -> {
            log.debug("洗水壶");
            sleep(1);
            log.debug("烧开水");
            sleep(5);
            synchronized (lock) {
                kettle = "开水";
                lock.notifyAll();
            }
        }, "老王").start();
​
        new Thread(() -> {
            log.debug("洗茶壶");
            sleep(1);
            log.debug("洗茶杯");
            sleep(2);
            log.debug("拿茶叶");
            sleep(1);
            synchronized (lock) {
                tea = "花茶";
                lock.notifyAll();
            }
        }, "小王").start();
​
        new Thread(() -> {
            synchronized (lock) {
                while (kettle.equals("冷水") || tea == null) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("拿({})泡({})", kettle, tea);
            }
        }, "王夫人").start();
​
    }
}

输出

20:13:18.202 c.S3 [小王] - 洗茶壶
20:13:18.202 c.S3 [老王] - 洗水壶
20:13:19.206 c.S3 [小王] - 洗茶杯
20:13:19.206 c.S3 [老王] - 烧开水
20:13:21.206 c.S3 [小王] - 拿茶叶
20:13:24.207 c.S3 [王夫人] - 拿(开水)泡(花茶)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/693356.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前后端分离开发及项目部署流程】

文章目录 前后端分离开发技术1 前后端分离开发1.1 介绍1.2 开发流程1.3 前端技术栈(了解) 2 Yapi(定义API接口)2.1 介绍2.2 使用 3 Swagger3.1 介绍3.2 使用方式3.3 常用注解 4 项目部署4.1 部署架构4.2 部署环境说明4.3 部署前端…

chatgpt赋能python:如何使用Python访问共享目录——让共享变得简单易行

如何使用Python访问共享目录 —— 让共享变得简单易行 作为一种高效而强大的编程语言,Python拥有各种各样的应用。其中一个非常重要的应用场景就是对共享目录的访问和操作。无论是在家庭网络,企业内网或者云存储平台,共享目录的重要性毋庸置…

两个链表的入环节点(java)

两个链表的入环节点 两个链表的入环节点解题思路代码演示 链表相关的题 两个链表的入环节点 给定两个可能有环也可能无环的单链表,头节点head1和head2 请实现一个函数,如果两个链表相交,请返回相交的第一个节点。如果不相交返回null 要求如果…

ATTCK(一)之为什么要学习ATTCK

ATT&CK 简介 本系列旨在介绍网络红蓝对抗领域最好的ATT&CK矩阵模型,以期帮助有意愿深耕在红蓝对抗领域的人员能系统性的掌握红蓝对抗领域的知识和经验。本系列将详细ATT&CK的起源、发展历史,ATT&CK矩阵相对其他High-Level红蓝对抗模型…

Redis7【② Key通用命令 十大数据类型】

1 Key的通用命令 redis命令不区分大小写,但是key是区分大小写的。没有返回值的命令执行成功会返回1,失败返回0。 1. KEYS 查看所有的key,返回值是一个数组 2. EXISTS EXISTS key [key ...]:返回给定的key中已存在的个数&#xf…

前端Vue自定义验证码密码登录切换tabs选项卡标签栏标题栏 验证码登录模版 密码登录模版

前端Vue自定义验证码密码登录切换tabs选项卡标签栏标题栏 验证码登录模版 密码登录模版, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id13221 效果图如下: 实现代码如下: # cc-selectBox #### 使用方法 使…

【计算机网络】可靠传输的实现机制

1、停止-等待协议SW 信道利用率 题目 小结 2.回退N帧协议GBN Go-Back-N 题目 小结

设计模式3:单例模式:JMM与volatile和synchronized的关系

本文目录 JMM简介Java 内部内存模型(The Internal Java Memory Model)硬件内存架构(Hardware Memory Architecture)弥合 Java 内存模型和硬件内存架构之间的差距(Bridging The Gap Between The Java Memory Model And The Hardware Memory Architecture)1.共享对象的可见性2.竞…

OpenStack(T版)——计算(Nova)服务介绍与安装

文章目录 OpenStack(T版)——计算(Nova)服务介绍与安装安装与配置(controller)准备(1)创建数据库(2)加载环境变量(3)创建认证服务凭据(4)创建Nova计算服务组件的API endpoint 安装和配置Nova计算服务组件(1)安装软件包(2)编辑/etc/nova/nova.conf 完成以下操作(3)同步数据库验证…

云服务器Linux防火墙云锁安装部署及使用 技术支持服务器安全运维

服务器必备安全防护及运维管理SAAS解决方案,支持windows/linux服务器跨平台实时、批量、远程安全管理,有效对抗服务器入侵和网络攻击。 服务器:Redhat/CentOS/Ubuntu/SUSE/中标麒麟 64位 Web中间件:Apache/Nginx/kangle/Tomcat/W…

【软考网络管理员】2023年软考网管初级常见知识考点(26)- HTML常见属性标签、表格、表单详解

涉及知识点 Html的概念,html常见标签,html常见属性,html表格,html表单,软考网络管理员常考知识点,软考网络管理员网络安全,网络管理员考点汇总。 原创于:CSDN博主-《拄杖盲学轻声码…

5-2图像处理经典案例:正弦噪声图像去噪

学习目标: 图像处理经典案例 去除噪声 1.简述 图像降噪的英文名称是Image Denoising, 图像处理中的专业术语。是指减少数字图像中噪声的过程,有时候又称为图像去噪。图像的噪声来源相对复杂,搞清楚图像噪声的成因对我们进行…

B+树

B树 B树是对B树的一种变形树,它与B树的差异在于: 非叶结点仅具有索引作用,也就是说,非叶子结点只存储key,不存储value 树的所有叶结点构成一个有序链表,可以按照key排序的次序遍历全部数据 B树存储数据 若参数M选…

使用影刀RPA拆分excel数据

首先,要使程序有一定的兼容性,即增加互动性,认为选择要拆分的文件和拆分的依据列,可以利用影刀中的‘打开选择对话框’和‘打开输入对话框’来实现,这样一来便不用考虑待拆分excel的路径问题获取1中选择的依据拆分列&a…

登录框界面之渗透测试思路总结

前言 大家都知道,渗透的过程中,遇见登录框是很常见的。下面就简单总结一下渗透中遇见登录页面的思路: 首先登录页面可能产生哪些漏洞呢? 1、弱密码与暴力破解 2、万能密码、SQL与XSS(注入) 3、登录时&…

渗透测试自动化报告脚本-----Nessus报告自动化解析--1-html解析

本专栏内容主要用于渗透测试工程师应对在工作中的自动化操作难题,高效摸鱼专用 解决问题 1、对Nessus导出的html报告进行自动化的提取操作,包括IP地址,漏洞个数,漏洞等级,漏洞描述,CVE编号等 2、由于Nes…

配置文件的优先级及maven打包和参数(port)的修改

1、配置文件的优先级 SpringBoot中支持五种配置格式:优先级:命令行参数(–xxxxxx) > java系统属性(-Dxxx xxx) > application.properties > application.yml > application.yaml 虽然springboot支持多种格式配置文件,但是在项目开发时&…

智能仓储货架的电子标签解决方案

近年来,电商和新零售行业的迅猛增长催生了仓储管理场景和运营模式的变革。企业不断寻求“低成本”和“更可靠”的解决方案,加快了仓储管理从粗放型向精细化转变的步伐。仓储管理的技术变革从机械化走向自动化,仓储数智化成为主流趋势。在这个…

chatgpt赋能python:Python语言冒泡排序-深入了解

Python语言冒泡排序 - 深入了解 冒泡排序是一种基本的排序算法,也是学习排序算法的入门算法之一。在Python中,我们可以很容易地实现冒泡排序。 冒泡排序的原理 冒泡排序的原理很简单,大概分为以下几个步骤: 比较相邻的元素&am…

Jnpf低代码开发平台

一、写在前面 低代码开发平台,一个号称能在几分钟的时间里开发出一套公司内部都可使用的应用系统开发工具。 很多人或许都隐隐听说过低代码,因为低代码不仅远名国外,国内的腾讯、阿里、华为、网易、百度等科技巨头也纷纷入局,足以…