Java多线程运行探幽
2022/3/30 22:19:33
本文主要是介绍Java多线程运行探幽,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
事关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"); } } }
结果、证实与猜想
- start()只是启动该线程(变为Runnable状态),运行与否以及运行多少均未知(看操作系统调度?),打印
depart
显然不能划分两个线程的先后 - 不要尝试去规划多线程运行的具体情况。根据代码不同,编译后乃至运行时的顺序会变;(不知是那一层的原因,什么编译优化、运行优化啥啥不懂)(相同代码生成的程序反复运行,结果一样,不过这也可能是在相邻的时间段内,运行环境一样)
对打印语句进行调整,看运行顺序:
情况1:(1)、(2)行均不注释
顺序: 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)行不注释
顺序: consumer打印start -> producer使用put方法 -> ...
我们并不知consumer线程何时让给了producer,但确乎是因为producer中少了一开始的打印start语句。可能经过了什么权衡先运行producer去了
情况3:(1)行不注释,(2)行注释
顺序: consumer使用get方法 -> ...
似乎又回到了情况1,consumer一开始就进入了线程同步的方法,运行到底后在交给producer。(很合理)
情况4:(1)、(2)均注释
顺序: producer使用put方法 -> ...
似乎回到了情况2,producer一开始就进入线程同步的方法,运行到底...
以上四种情况对比后,大致可以猜想,两个线程运行且没有特殊线程控制语句干扰时,会以某种单位划分(CPU时间?代码块大小?)进行交替运行,这里体现为一行行语句交替。
突然想到操作系统课上好像讲过多道程序balabala、多线程运行的CPU时间分配啥啥,感觉这样鼓捣了半天去验证有点傻
这篇关于Java多线程运行探幽的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-04-26敏捷开发:想要快速交付就必须舍弃产品质量?
- 2024-04-26静态代码分析的这些好处,我竟然都不知道?
- 2024-04-26你在测试金字塔的哪一层?(下)
- 2024-04-26快刀斩乱麻,DevOps让代码评审也自动起来
- 2024-04-262024年最好用的10款ER图神器!
- 2024-04-2203-为啥大模型LLM还没能完全替代你?
- 2024-04-2101-大语言模型发展
- 2024-04-17基于SpringWeb MultipartFile文件上传、下载功能
- 2024-04-14个人开发者,Spring Boot 项目如何部署
- 2024-04-14RAG应用开发实战02-相似性检索的关键 - Embedding