事关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)行均不注释

顺序: 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多线程运行探幽的更多相关文章

  1. Java多线程运行机制的基本原理

    Java多线程运行机制的基本原理 进程和线程的区别 进程 进程是一个程序执行的实例,比如说我们打开10个IE浏览器窗口,那么就有10个进程开启.一个进程可以同时被运行若干次,进程是CPU进行资源分配和 ...

  2. Java基础知识强化之多线程笔记05:Java程序运行原理 和 JVM的启动是多线程的吗

    1. Java程序运行原理:     Java 命令会启动Java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程.该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 m ...

  3. 40个Java多线程问题总结

    前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...

  4. Java多线程基础知识篇

    这篇是Java多线程基本用法的一个总结. 本篇文章会从一下几个方面来说明Java多线程的基本用法: 如何使用多线程 如何得到多线程的一些信息 如何停止线程 如何暂停线程 线程的一些其他用法 所有的代码 ...

  5. Java多线程系列--“JUC锁”04之 公平锁(二)

    概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...

  6. Java多线程--让主线程等待子线程执行完毕

    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...

  7. Java多线程 2 线程的生命周期和状态控制

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...

  8. java 多线程 1 线程 进程

    Java多线程(一).多线程的基本概念和使用 2012-09-10 16:06 5108人阅读 评论(0) 收藏 举报  分类: javaSE综合知识点(14)  版权声明:本文为博主原创文章,未经博 ...

  9. 第一章 Java多线程技能

    1.初步了解"进程"."线程"."多线程" 说到多线程,大多都会联系到"进程"和"线程".那么这两者 ...

  10. java从基础知识(十)java多线程(下)

    首先介绍可见性.原子性.有序性.重排序这几个概念 原子性:即一个操作或多个操作要么全部执行并且执行的过程不会被任何因素打断,要么都不执行. 可见性:一个线程对共享变量值的修改,能够及时地被其它线程看到 ...

随机推荐

  1. iaas,saas,paas,daas区别:

    iaas,saas,paas,daas区别: Iaas(Infrastructure as a server):基础设施即服务,是基础层.PaaS(Platform as a Server):平台即服 ...

  2. 【FAQ】HarmonyOS SDK 闭源开放能力 — Vision Kit(2)

    1.问题描述: 人脸活体检测返回上一页App由沉浸式变为非沉浸式多了上下安全区域. 解决方案: 检测结束后需要自己去设置沉浸式配置. 2.问题描述: Vision Kit文字识别是本地识别,还是上传至 ...

  3. Qt/C++音视频开发58-逐帧播放/上一帧下一帧/切换播放进度/实时解码

    一.前言 逐帧播放是近期增加的功能,之前也一直思考过这个功能该如何实现,对于mdk/qtav等内核组件,可以直接用该组件提供的接口实现即可,而对于ffmpeg,需要自己处理,如果有缓存的数据的话,可以 ...

  4. Qt音视频开发12-easyplayer内核

    一.前言 在视频监控行业经常看到两个厂家广告打得比较厉害,一个是青犀视频对应easyplayer,一个是大牛直播,两个最初都是sdk免费,并提供调用示例源码,后面大牛直播的sdk以及示例都无法运行,目 ...

  5. Qt编写物联网管理平台30-用户登录退出

    一.前言 一个用户登录界面,是一个完整的应用系统,尤其是客户端系统必备的一个功能模块,传统的登录处理一般都是和本地的用户信息进行比对,而现代的登录系统一般是发送请求到服务器进行验证,无论何种方式,都是 ...

  6. Qt编写地图综合应用32-区域地图

    一.前言 echart本身是没有提供省市区域轮廓图的,需要引入外部的js文件才能绘制,为了拿到全国各省市的对应轮廓图js文件,特意去网上搜索了很多的相关文章并理解,下载到了对应的省市区域的json数据 ...

  7. 9.4java考试订正

    import java.util.Scanner; public class viovo { static int number = 5;//五个商品信息 static oppo[] s = new ...

  8. [转]Ceres求解优化问题

    1. 简介Ceres Solver是专门用于求解非线性最小二乘问题的C++开源库,研究SLAM方向不过滤波和优化两个技术路线,因此常用Ceres库解决实际项目中的优化问题,当然还有g2o同样可用,但就 ...

  9. 开源即时通讯IM框架MobileIMSDK的H5端技术概览

    一.基本介绍 MobileIMSDK的H5端是一套纯JS编写的基于标准WebSocket的即时通讯库: 1)超轻量级.极少依赖: 2)纯JS编写.高度提炼,简单易用: 3)基于标准WebSocket协 ...

  10. IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

    1.引言 在中大型IM系统中,聊天消息的唯一ID生成策略是个很重要的技术点.不夸张的说,聊天消息ID贯穿了整个聊天生命周期的几乎每一个算法.逻辑和过程,ID生成策略的好坏有可能直接决定系统在某些技术点 ...