ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java多线程运行探幽

2022-03-30 20:32:00  阅读:158  来源: 互联网

标签:Java producer content 线程 put 探幽 多线程 consumer 运行


事关Training2中Task4,想看看经典的两个进程并行会是什么样子

题目概述

实现简单的生产者-消费者模型

  • Tray托盘容量为1;托盘满时不能放入,空时不能取货
  • Producer生产者共需生产10个货物;每生产一个货物后会立刻尝试放入,放入成功前不会继续生产,货物按照从1-10编号;成功放入货物后需要休息0-100ms
  • Consumer消费者共需消费10个货物;只能在托盘中取货。

输出:

  • Producer放入货物时输出: "Producer put:" + 货物编号
  • Consumer取出货物时输出: "Consumer get:" + 货物编号

基本代码

为了精确定轨当前代码运行位置,在多出放置System.out.println()并表上颜色;

为了方便将10改成3

public class Task4 {
    public static Tray TRAY = new Tray();
    public static void main(String[] args) {
        Thread producer = new Producer();
        Thread consumer = new Thread(new Consumer());
        producer.start();
        System.out.println("\033[32m" + "==== Depart ====" + "\033[0m");
        consumer.start();
    }
}

class Tray {
    private int content;
    private boolean full;

    Tray() {
        content = 0;
        full = false;
    }

    public synchronized void put(int content) {
        while (full) {
            try {
                System.out.println("\t[Producer] nowhere for content " + content + "! wait for get...");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.content = content;
        this.full = true;
        System.out.println("Producer put:" + content);
        notifyAll();
    }

    public synchronized void get() {
        while (!full) {
            try {
                System.out.println("\t[Consumer] Nothing in tray! wait for put...");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.full = false;
        System.out.println("Consumer get:" + content);
        notifyAll();
    }
}

class Producer extends Thread {
    public void run() {
        for (int i = 1; i <= 3; ++i) {
            /*(1)行*/System.out.println("\033[32m" + "Start putting " + i + "\033[m");
            Task4.TRAY.put(i);
            try {
                System.out.println("\033[32m" + "Put finished! sleep for a while..." + "\033[m");
                sleep((int) (Math.random() * 100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("\033[32m" + "[switch to next]" + "\033[m");
        }
    }

}

class Consumer extends Thread {
    public void run() {
        for (int i = 1; i <= 3; ++i) {
            /*(2)行*/System.out.println("\033[31m" + "Start Getting" + "\033[0m");
            Task4.TRAY.get();
            System.out.println("\033[31m" + "Get finished!\n[switch to next]" + "\033[0m");
        }
    }
}

结果、证实与猜想

  1. start()只是启动该线程(变为Runnable状态),运行与否以及运行多少均未知(看操作系统调度?),打印depart显然不能划分两个线程的先后
  2. 不要尝试去规划多线程运行的具体情况。根据代码不同,编译后乃至运行时的顺序会变;(不知是那一层的原因,什么编译优化、运行优化啥啥不懂)(相同代码生成的程序反复运行,结果一样,不过这也可能是在相邻的时间段内,运行环境一样)

对打印语句进行调整,看运行顺序:

情况1:(1)、(2)行均不注释

image

顺序: consumer打印start -> consumer使用get方法 -> consumer无效get进行等待 -> producer打印start -> producer进行put方法 -> ...

(sychronized中wait()后,循环的notify使得双线程的运行可预知(?))

producer进行put方法的最后,会唤醒等待的consumer,但consumer并没有直接运行,而是等producer运行至进入休眠,才接入cpu时间开始运行。
强调:notify()等方法只是将线程从"Waiting"状态变为"Runnable"状态,是否"Run"未可知。

情况2:(1)行注释,(2)行不注释

image

顺序: consumer打印start -> producer使用put方法 -> ...

我们并不知consumer线程何时让给了producer,但确乎是因为producer中少了一开始的打印start语句。可能经过了什么权衡先运行producer去了

情况3:(1)行不注释,(2)行注释

image

顺序: consumer使用get方法 -> ...

似乎又回到了情况1,consumer一开始就进入了线程同步的方法,运行到底后在交给producer。(很合理)

情况4:(1)、(2)均注释

image

顺序: producer使用put方法 -> ...

似乎回到了情况2,producer一开始就进入线程同步的方法,运行到底...

以上四种情况对比后,大致可以猜想,两个线程运行且没有特殊线程控制语句干扰时,会以某种单位划分(CPU时间?代码块大小?)进行交替运行,这里体现为一行行语句交替。

突然想到操作系统课上好像讲过多道程序balabala、多线程运行的CPU时间分配啥啥,感觉这样鼓捣了半天去验证有点傻

标签:Java,producer,content,线程,put,探幽,多线程,consumer,运行
来源: https://www.cnblogs.com/elucidator-xrb/p/16078934.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有