经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
Java并发(十二)----线程应用之多线程解决烧水泡茶问题
来源:cnblogs  作者:|旧市拾荒|  时间:2023/6/28 8:50:17  对本文有异议

1、背景

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

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

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

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

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

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

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

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

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

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

 

2、思路

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

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

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

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

3、解法1:join

  1. @Slf4j(topic = "c.Test16")
  2. public class Test16 {
  3. ?
  4.    public static void main(String[] args) {
  5.        Thread t1 = new Thread(() -> {
  6.            log.debug("洗水壶");
  7.            // TimeUnit.SECONDS.sleep(i);
  8.            sleep(1);  // sleep 1s 可使用上方的代码睡眠
  9.            log.debug("烧开水");
  10.            sleep(5); // sleep 5s
  11.       },"老王");
  12. ?
  13.        Thread t2 = new Thread(() -> {
  14.            log.debug("洗茶壶");
  15.            sleep(1); // sleep 1s
  16.            log.debug("洗茶杯");
  17.            sleep(2); // sleep 2s
  18.            log.debug("拿茶叶");
  19.            sleep(1); // sleep 1s
  20.            try {
  21.                t1.join();
  22.           } catch (InterruptedException e) {
  23.                e.printStackTrace();
  24.           }
  25.            log.debug("泡茶");
  26.       },"小王");
  27. ?
  28.        t1.start();
  29.        t2.start();
  30.   }
  31. }

输出

解法1 的缺陷:

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

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

4、解法2:wait/notify

  1. class S2 {
  2.    static String kettle = "冷水";
  3.    static String tea = null;
  4.    static final Object lock = new Object();
  5.    static boolean maked = false;
  6. ?
  7.    public static void makeTea() {
  8.        new Thread(() -> {
  9.            log.debug("洗水壶");
  10.            sleep(1);
  11.            log.debug("烧开水");
  12.            sleep(5);
  13.            synchronized (lock) {
  14.                kettle = "开水";
  15.                lock.notifyAll();
  16.                while (tea == null) {
  17.                    try {
  18.                        lock.wait();
  19.                   } catch (InterruptedException e) {
  20.                        e.printStackTrace();
  21.                   }
  22.               }
  23.                if (!maked) {
  24.                    log.debug("拿({})泡({})", kettle, tea);
  25.                    maked = true;
  26.               }
  27.           }
  28.       }, "老王").start();
  29. ?
  30.        new Thread(() -> {
  31.            log.debug("洗茶壶");
  32.            sleep(1);
  33.            log.debug("洗茶杯");
  34.            sleep(2);
  35.            log.debug("拿茶叶");
  36.            sleep(1);
  37.            synchronized (lock) {
  38.                tea = "花茶";
  39.                lock.notifyAll();
  40.                while (kettle.equals("冷水")) {
  41.                    try {
  42.                        lock.wait();
  43.                   } catch (InterruptedException e) {
  44.                        e.printStackTrace();
  45.                   }
  46.               }
  47.                if (!maked) {
  48.                    log.debug("拿({})泡({})", kettle, tea);
  49.                    maked = true;
  50.               }
  51.           }
  52.       }, "小王").start();
  53.   }
  54. }

输出

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

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

5、解法3:第三者协调

  1. class S3 {
  2.    static String kettle = "冷水";
  3.    static String tea = null;
  4.    static final Object lock = new Object();
  5. ?
  6.    public static void makeTea() {
  7.        new Thread(() -> {
  8.            log.debug("洗水壶");
  9.            sleep(1);
  10.            log.debug("烧开水");
  11.            sleep(5);
  12.            synchronized (lock) {
  13.                kettle = "开水";
  14.                lock.notifyAll();
  15.           }
  16.       }, "老王").start();
  17. ?
  18.        new Thread(() -> {
  19.            log.debug("洗茶壶");
  20.            sleep(1);
  21.            log.debug("洗茶杯");
  22.            sleep(2);
  23.            log.debug("拿茶叶");
  24.            sleep(1);
  25.            synchronized (lock) {
  26.                tea = "花茶";
  27.                lock.notifyAll();
  28.           }
  29.       }, "小王").start();
  30. ?
  31.        new Thread(() -> {
  32.            synchronized (lock) {
  33.                while (kettle.equals("冷水") || tea == null) {
  34.                    try {
  35.                        lock.wait();
  36.                   } catch (InterruptedException e) {
  37.                        e.printStackTrace();
  38.                   }
  39.               }
  40.                log.debug("拿({})泡({})", kettle, tea);
  41.           }
  42.       }, "王夫人").start();
  43. ?
  44.   }
  45. }

输出

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

 

 

原文链接:https://www.cnblogs.com/xiaoyh/p/17092390.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号