首页 > 编程语言 >Java并发(十二)----线程应用之多线程解决烧水泡茶问题

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

时间:2023-06-27 21:33:26浏览次数:48  
标签:Java log lock ---- sleep 小王 debug 20 多线程

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 [王夫人] - 拿(开水)泡(花茶)

 

 

标签:Java,log,lock,----,sleep,小王,debug,20,多线程
From: https://www.cnblogs.com/xiaoyh/p/17092390.html

相关文章

  • 一致性哈希的设计理念
    首先看一个最简单的hash函数#defineHASH_RANGE5intsimple_hash(intkey){returnkey%HASH_RANGE}通过调用simple_hash对5、8、9三个值进行哈希,结果如下:simple_hash(5)=0simple_hash(8)=3simple_hash(9)=4在实际应用中,HASH_RANGE是代表着一定的实际意义的,比如......
  • 再思linux内核在中断路径内不能睡眠/调度的原因(2010)
    Linux内核中断路径中不能睡眠,为什么? 这里就行了很深入的讨论,值得一看:http://bbs.chinaunix.net/viewthread.php?tid=1618430 但是,他们的讨论最后没有得出一个明确的结论。其中,cskyrain在8楼的思考触及到了一个要点,但是没有深入展开: 1楼发表于2009-11-2420:36|只看该作者......
  • Qemu中生成针对具体体系结构的纯净代码的方法---利用GCC的-E选项
      实验室正在研究一个叫做Qemu的项目,外国人写的初始代码。里面很多内容是我们不需要的,但是却参杂在我们关注的代码中。突然想到了一个编译命令-E,它能够一下子就把那些不需要的代码过滤掉。以前几次开会大家都抱怨这个东西干扰信息太多,导致代码分析的连贯性总是被打断,进度特别慢......
  • redis压缩列表ziplist
     压缩列表(ziplist)是Redis的一种内存紧凑型的数据结构,它是一个字节数组,可以包含任意多个元素,每个元素可以是一个字节数组或一个整数。压缩列表的结构由多个字段组成,包括zlbytes(压缩列表的字节长度),zltail(压缩列表尾元素的偏移量),zllen(压缩列表的元素数目),entryX(压缩列表存储的......
  • Python一个有趣的彩蛋
    上周组内技术分享会,朋友介绍了Python语言有趣的历史,其中一个有意思的环节就是Python之禅,或者叫Python的彩蛋-this.py,命令行执行python-c"importthis"或者在python解释器中执行importthis,会打印出如下的一段英文,TheZenofPython,byTimPetersBeautifulisbetterthanug......
  • 基于MySQL+SpringBoot+IDEA开放的绩效评估系统
    基于MySQL+SpringBoot+IDEA开放的绩效评估系统项目介绍......
  • 作为开篇文章,我们聊聊“围城”
    刚刚经过的2021年,又是不寻常的一年,人们正在适应和疫情共存的生活,推迟的奥运会、欧洲杯,相继举行,国内的各种联赛,采用了赛会制,男足世界杯亚洲预选赛,还是如同预期,进行到了一半,基本可以开始准备下届了。作为新的一年的开篇,先给各位朋友们讲一个小故事。如果关注中国足球的朋友,或者北京的......
  • 体验云资源
    现在云资源已经很普遍了,碰巧腾讯TVP项目给了一些代金券,尝试一下腾讯云,登陆腾讯云,点击云产品,可以看到所有他能提供的云产品,一般常用的就是云服务器(CloudVirtualMachine,CVM),他强调的是提供安全可靠的弹性计算服务,可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资......
  • 阿里的Java开发规范插件验证
    阿里最近有点“烦”,但是作为技术人,更多关注的还是技术层面,其他的就交给有关机构和时间来证明。最近有项工作借鉴了阿里的Java开发规范,为了能让其落地,需要验证方案,而这个Java开发规范提供了对应的验证插件,因此从使用层面,了解一下。目前该插件实现了开发手册中的的53条规则,大部分基于......
  • 鸿蒙星空的太白星 | WebView给元服务调用JS API指明方向
    ​漆黑深夜夜凉如水,繁星盛开于无垠苍穹。清风徐来,一片薄云,夜空顿然失色,有些阴霾。天空中最亮的星,太白星,在薄云中依然闪耀,如同海上迷雾中的灯塔,为迷失方向的船只指明方向。 元服务是华为提供的一种面向未来的服务形态,具有独立入口和免安装等特性,支持运行在1+8+N设备上。在万物互......