多线程的初识和创建
✨个人主页:bit me👇
✨当前专栏:Java EE初阶👇
✨每日一语:知不足而奋进,望远山而前行。
目 录
- 💤一. 认识线程(Thread)
- 🍎1. 线程的引入
- 🍏2. 线程是什么?
- 🍋3. 进程和线程之间的区别
- 💨二. 第一个多线程程序
- 🏐1. Java中线程的认识和基本操作
- 🥎2. 线程的查看
- 🎶三. 创建线程的几种常见写法
- 💦四. 多线程的优势
- ❄️五. 多线程的使用场景
💤一. 认识线程(Thread)
🍎1. 线程的引入
- 根据我们前面学的进程,为什么要有多个进程呢?为了并发编程,他的 CPU 单个核心已经发挥到极致了,想要提升算力,就得使用多个核心。
- 引入并发编程,最大的目的就是为了能够充分的利用好 CPU 的多核资源。使用多进程这种编程模型,是完全可以做到。并发编程,并且也能够使 CPU 多核被充分利用,但是在有些情急下,会存在问题,例如:需要频繁的创建 / 销毁进程,这个时候就会比较低效!!!
- 例如,你写了个服务器程序,服务器要同一时刻给很多客户提供服务的,就需要用到并发编程,典型的做法,就是每个客户端给他分配一个进程,提供一对一服务。
创建 / 销毁进程,本身就是一个比较低效的操作
1. 创建 PCB
2. 分配系统资源(尤其是内存资源)分配资源,就比较消耗时间了!(这个是在系统内核资源管理模块进行一系列操作的...)
3. 把 PCB 加入到内核的双向链表中
为了提高这个场景下的效率,就引入了 " 线程 ",线程其实也叫做 " 轻量级进程 "
🍏2. 线程是什么?
一个线程其实是包含在进程中的(一个进程里面可以有很多个线程),每个线程其实也有自己的 PCB (一个进程里面可能就对应多个 PCB),同一个进程里面的多个线程之间,共用一份系统资源(意味着,新创建的线程,不必重新给他分配系统资源,只需要复用之前的即可!)
因此,创建线程只需要
1. 创建 PCB
2. 把 PCB 加入到内核的链表中
这就是线程相对于进程做出的重大改进!!!也就是线程更轻量的原因!
- 创建线程比创建进程更快,开销更小.
- 销毁线程比销毁进程更快,开销更小.
- 调度线程比调度进程更快.
线程,是包含在进程内部的 " 逻辑执行流 "(线程可以执行一段单独的代码,多个线程之间,是并发执行的)
操作系统进行调度的时候,其实也是以 " 线程为单位 " 来进行调度的(系统内核不认进程 / 线程,只认 PCB)
如果把进程比作工厂,线程就是工厂内部的流水线
🍋3. 进程和线程之间的区别
进程是包含线程的,线程是在进程内部的
每个进程有独立的虚拟地址空间(进程之间的资源是独立的,进程的独立性),也有自己独立的文件描述符表;同一个进程(不同进程里面的不同线程,则没有共享的资源)的多个线程之间,则共用这一份虚拟地址空间和文件描述符表(线程之间系统资源是共享的)
进程是操作系统中资源分配的基本单位,线程是操作系统中,调度执行的基本单位
多个进程同时执行的时候,如果一个进程挂了,一般不会影响到别的进程;同一个进程内的多个线程之间,如果一个线程挂了,很可能把整个进程带走,其他同进程里的线程也就没了
💨二. 第一个多线程程序
🏐1. Java中线程的认识和基本操作
在 Java 中即使是一个最简单的 “hello”,其实在运行的时候也涉及到线程了,一个进程里至少会有一个线程
public static void main(String[] args) {System.out.println("hello");
}
运行上面的程序,操作系统就会创建一个 Java 进程,在这个 Java 进程里就会有一个线程(主线程)调用 main 方法;虽然在上述代码中,我们并没有手动的创建其他线程,但是 Java 进程在运行的时候,内部也会创建多个线程。
注:
谈到多进程的时候,经常会谈到 “父进程” “子进程”。进程 A 里面创建了进程 B,A 是 B 的父进程,B 是 A 的子进程。但是在多线程里面,没有 “父线程” “子线程” 这种说法,线程之间的地位是对等的!
创建一个线程,Java 中创建线程,离不开一个关键的类,Thread。一种比较朴素的创建线程的方式,是写一个子类,继承 Thread,重写其中的 run 方法。
class MyTread extends Thread {@Overridepublic void run() {System.out.println("hello Thread!");}
}
这个 run 方法重写的目的,是为了明确咱们新创建出来的线程,要干啥活儿
光创建了这个类,还不算创建线程,还得创建实例
,在主函数中写如下代码
Thread t = new MyTread();
t.start();
- System.out.println(“hello Thread!”); --> 先把新员工要做的任务安排好
- Thread t = new MyTread(); --> 招聘进来一个新员工,把任务交给他
- t.start(); --> 告诉新员工,你开始干活!
t.start(); --> 这才是真正开始创建线程(在操作系统内核中,创建出对应线程的 PCB,然后让这个 PCB 加入到系统链表中,参与调度)
Thread t = new MyTread();
t.start();System.out.println("hello main!");
在这个代码中,虽然先启动的线程,后打印的 hello main,但是实际执行的时候,看到的却是先打印了 hello main 后打印了 hello thread。
- 每个线程是独立的执行流!main 对应的线程是一个执行流,MyThread 是另一个执行流,这两个执行流之间是并发(并发+并行)的执行关系!
- 此时两个线程执行的先后顺序,取决于操作系统调度具体实现(程序猿可以把这里的调度规则简单的视为是 “随机调度”)
因此执行的时候看到,是先打印 hello main 还是先打印 hello thread 是不能确定的。无论反复运行多少次看起来好像都是先打印 hello main,但是顺序仍然是不能确定的,当前看到的先打印 main,大概率是受到创建线程自身的开销影响的。
编写多线程代码的时候,一定要注意到!!!默认情况下,多个线程的执行顺序,是 “无序”,是 "随机调度"的。
我们还有一些手段能影响到线程执行的先后顺序的,但是调度器自身的行为修改不了,调度器仍然是随机调度,咱们最多是让某个线程先等待,等待另一个线程执行完了自己再执行
- Process 进程
- exit code 0 进程的退出码
操作系统中用 进程的退出码 来表示 “进程的运行结果”
- 使用 0 表示进程执行完毕,结果正确
- 使用非 0 表示进程执行完毕,结果不正确
- 还有个情况 main 还没返回,进程就崩溃,此时返回的值很可能是一个随机值
要是我们不想要这个程序结束的这么快咋办?
就可以想办法让这个进程别结束这么快,好让咱们看下这里都有啥线程
while (true) {System.out.println("hello Thread!");
}
while (true){System.out.println("hello main!");
}
把他们都套上一个死循环之后看到打印结果是 hello main! 和 hello Thread! 交替打印
🥎2. 线程的查看
(注意不要关闭上述程序运行,查看线程需要)此时就可以查看当前 Java 进程里的线程有哪些(打开任务管理器可以观看到程序运行状态)
- 找出 JDK 安装的目录,找到 bin 文件里,在 JDK 里提供了 jconsole这样的工具,可以看到 Java 进程里的线程详情
- 点击运行(如果运行界面没有这样的选项,我们在打开的时候需要以管理员方式打开!)
- 点击进去即可(不用害怕hhh)
- 打开线程所在窗口
- 找到左下角,会有显示具体的线程
这个列表就是当前 Java 进程中的线程信息
其他的线程则是 JVM 中的辅助功能,有的线程负责垃圾回收,有的线程负责处理调试信息,比如咱们使用的 jconsole 能够连上这个 JVM ,也是靠对应的线程提供的服务
- 点击某个线程的时候,右侧会显示线程的详细情况
上面两张表里都描述了当前线程这里的各种方法之间调用的关联关系
这里的调用栈非常有用,未来调试一个 “卡死” 的程序的时候,就可以看下面每个线程的调用栈是啥,就可以初步的确认卡死的原因。
上面的死循环代码打印的太快太多,有时候我们不希望它这么快,不利于我们观察,于是用 sleep 来让线程适当休息一下
使用
Thread.sleep
的方式进行休眠,sleep 是Thread 的静态成员方法,sleep 的参数是一个时间,单位 ms
这个异常在多线程中经常能见到,
interrupted 中断
通过 try-catch 抓捕异常后的运行结果
加上 sleep 之后,无序调度这个事情就被更加清楚的观察到了。
一个经典面试题:
谈谈 Thread 的 run 和 start 的区别:
- 使用 start 可以看到两个线程并发的执行,两组打印交替出现
- 使用 run 可以看到只是在打印 thread,没有打印 main
直接调用 run 并没有创建新的线程,而只是在之前的线程中,执行了 run 里的内容;使用 start,则是创建新的线程,新的线程里面会调用 run,新线程和旧线程之间是并发执行的关系
上述总的代码:
class MyTread extends Thread {@Overridepublic void run() {while (true) {System.out.println("hello Thread!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class Demo1 {public static void main(String[] args) {//创建一个线程//Java 中创建线程,离不开一个关键的类,Thread//一种比较朴素的创建线程的方式,是写一个子类,继承 Thread,重写其中的 run 方法。Thread t = new MyTread();//t.start();t.run();while (true){System.out.println("hello main!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}
}
🎶三. 创建线程的几种常见写法
- 创建一个类继承 Thread,重写 run。(上面已经写过)
这个写法,线程和任务内容是绑定在一起的!
- 创建一个类,实现 Runnable 接口,重写 run。
Runnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
此处创建的 Runnable,相当于是定义了一个 "任务"(代码要干啥)
需要 Thread 实例,把任务交给 Thread
还是 Thread.start 来创建具体的线程
- 这个写法,线程和任务是分离开的(更好的解耦合)(耦合的意思和表面差不多,模块 / 代码之间,关联关系越紧密,就认为耦合性越高,关联关系越不紧密,认为耦合性越低)
- 写代码的时候追求 “高耦合” “低内聚”,让每个模块之间耦合性降低, 好处就是一个模块出了问题对另外的模块影响不大
- 这种写法把任务内容和线程本身给分离开了,就把耦合性降低了(任务的本身和线程关系不大),假设这个任务不想通过多线程执行了,而是换成别的方式执行,这个时候代码的改动也不大。
一个问题:
为啥刚才使用 Thread,Runnable,interruptedException 都不需要 import ??啥样的类,不需要 import 就能直接使用??
- 要么是同一个类中,要么这个类是在 java.lang 中(String)
- 仍然是使用继承 Thread 类,但是不再显式继承,而是使用 “匿名内部类”。
public class Demo3 {public static void main(String[] args) {Thread t = new Thread() {@Overridepublic void run() {while(true){System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};t.start();}
}
Thread t = new Thread() {
此处就是在创建了一个匿名内部类(没有名字),这个匿名内部类是 Thread 的子类,同时前面 new 关键字,就给这个匿名内部类创建出了一个实例
这一套操作实现了继承,方法重写,实例化
在 start 之前,线程只是准备好了,并没有真正被创建出来,执行了 start 方法,才真正在操作系统中创建了线程!!
Thread 实例是 Java 中对于线程的表示,实际上想要真正的跑起来,还是需要操作系统里面的线程,创建好了 Thread,此时系统里面还没有线程,直到调用 start 方法,操作系统才真的创建了线程(1.创建 PCB;2.把 PCB 加入到链表里)并进行运行。
- 使用 Runnable,是匿名内部类的方式使用
- 方法一:
public class Demo4 {public static void main(String[] args) {Runnable runnable = new Runnable() {@Overridepublic void run() {while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}};Thread t = new Thread(runnable);t.start();}
}
- 方法二:(推荐)
public class Demo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while (true){System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}});t.start();}
}
中间的匿名内部类的实例,是 Thread 的构造方法的参数!
- 使用 lambda 表达式,来定义任务。(推荐做法)
public class Demo5 {public static void main(String[] args) {Thread t = new Thread(() -> {while (true){System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}
使用 lambda 表达式,其实是更简单的写法,也是推荐写法,形如 lambda 表达式这样的,能够简化代码编写的语法规则,称为 “语法糖”。
lambda 表达式本质上就仅仅是一个 “匿名函数”(没有名字的,只使用一次的函数)
实际上,线程还有其他的创建方式,后续介绍后面的创建方式!
6.基于 Callable / FutureTask 的方式创建
7.基于线程池的方式创建
至少有七种创建方式~
💦四. 多线程的优势
- 单个线程,串行的,完成 20 亿次自增。
public class Demo6 {private static final long COUNT = 20_0000_0000;private static void serial(){//需要把方法执行的时间给记录下来//记录当前的毫秒级时间戳long beg = System.currentTimeMillis();int a = 0;for(long i = 0; i < COUNT; i++){a++;}a = 0;for(long i = 0; i < COUNT; i++){a++;}long end = System.currentTimeMillis();System.out.println("单线程消耗的时间:" + (end - beg) + " ms");}public static void main(String[] args) {serial();}
}
运行结果:
使用一个线程串执行花了大约 1200 ms
- 两个线程,并发的,完成 20 亿次自增
public class Demo6 {private static void concurrency(){long beg = System.currentTimeMillis();Thread t1 = new Thread(()->{int a = 0;for(long i = 0; i < COUNT; i++){a++;}});Thread t2 = new Thread(()->{int a = 0;for(long i = 0; i < COUNT; i++){a++;}});t1.start();t2.start();long end = System.currentTimeMillis();System.out.println("并发执行的时间:" + (end - beg) + " ms");}public static void main(String[] args) {concurrency();}
}
这个代码涉及到三个线程 t1,t2,main(调用 concurrency 方法的线程),三个线程都是并发执行的
t1.start(); t2.start(); 表示 t1,t2 是会开始执行的,同时,不等 t1,t2 执行完毕,main 线程就往下走了,于是就结束计时。此处的计时,是为了衡量 t1,t2 的执行时间,正确的做法应该是等到 t1,t2 都执行完,才停止计时。
在上述代码 t1.start(); t2.start(); 之后加上如下代码即可
try {t1.join();t2.join();
} catch (InterruptedException e) {e.printStackTrace();
}
t1.join(); t2.join(); --> join 是等待线程结束(等待线程把自己的 run 方法执行完),在主线程中调用 t1.join,意思就是让 main 线程等待 t1 执行完,这两个 join 操作谁先谁后不影响。
运行结果:
如果没有 join 的限制,main 和 t1,t2 都是同时往下走的!多个线程并发执行的(同时在往下走),走的过程中,调度顺序不确定!调度在这个代码执行过程中不是只有一次,会有很多次,即使是上面的简单代码,也可能会出现成千上万次的调度!绝对不是说一个线程执行完了再调度给第二个线程!!!
上面的结果相较之下对比体现出两个线程并发执行确实快了不少,但是为什么两个线程并发执行不是单个线程串行执行的耗时一半呢?
创建线程自身,也是有开销的
两个线程在 CPU 上不一定是纯并行,也可能是并发(一部分时间并行了,一部分时间并发了)
线程的调度,也是有开销的
❄️五. 多线程的使用场景
- 在 CPU 密集型
代码中大部分工作,都是在使用 CPU 进行运算(就像上面的反复++),使用多线程,就可以更好的利用 CPU 多核计算资源,从而提高效率!
- 在 IO 密集型场景
input output ,读写硬盘,读写网卡…这些操作都算 IO,像这些 IO 操作,几乎都是不消耗 CPU 就能完成快速读写数据的操作,既然 CPU 在摸鱼,就可以给他找点活儿干,也可以使用多线程,避免 CPU 过于闲置。
相关文章:
多线程的初识和创建
✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 ✨每日一语:知不足而奋进,望远山而前行。 目 录💤一. 认识线程(Thread)🍎1. 线程的引入🍏2. 线程…...
一句话设计模式3:工厂模式
工厂模式:new多种对象的简单方式。 文章目录 工厂模式:new多种对象的简单方式。前言一、两种工厂模式二、如何实现工厂模式1. 简单工厂2. 抽象工厂总结前言 工厂模式可以说比较常见的设计模式,仔细观察在很多源码中都有此种模式的应用;用来解决创建对象的创建问题; 一、两种工…...
【Codeforces Round #853 (Div. 2)】C. Serval and Toxel‘s Arrays【题解】
题目 Toxel likes arrays. Before traveling to the Paldea region, Serval gave him an array aaa as a gift. This array has nnn pairwise distinct elements. In order to get more arrays, Toxel performed mmm operations with the initial array. In the iii-th opera…...
100天精通Python(数据可视化篇)——第77天:数据可视化入门基础大全(万字总结+含常用图表动图展示)
文章目录1. 什么是数据可视化?2. 为什么会用数据可视化?3. 数据可视化的好处?4. 如何使用数据可视化?5. Python数据可视化常用工具1)Matplotlib绘图2)Seaborn绘图3)Bokeh绘图6. 常用图表介绍及其…...
PMP考前冲刺2.27 | 2023新征程,一举拿证
题目1-2:1.在产品开发过程中,项目发起人向项目团队推荐了一种新材料,新材料比现有的材料更便宜而且性能更好。如果团队采用新材料,不但有利于提升产品质量,而且可以显著降低成本。项目经理应该怎么办?A.采用新材料&am…...
【C++】map和set的封装(红黑树)
map和set的封装一、介绍二、stl源码剖析三、仿函数获取数值四、红黑树的迭代器五、map的[]5.1 普通迭代器转const迭代器六、set源码七、map源码八、红黑树源码一、介绍 首先要知道map和set的底层都是用红黑树实现的 【数据结构】红黑树 set只需要一个key,但是map既…...
【批处理脚本】-1.14-移动文件(夹)命令move
"><--点击返回「批处理BAT从入门到精通」总目录--> 共10页精讲(列举了所有move的用法,图文并茂,通俗易懂) 在从事“嵌入式软件开发”和“Autosar工具开发软件”过程中,经常会在其集成开发环境IDE(CodeWarrior,S32K DS,Davinci,EB Tresos,ETAS…)中,…...
逻辑地址和物理地址转换
在操作系统的学习中,很多抵挡都会涉及虚拟地址转换为物理地址的计算,本篇就简单介绍一下在分页存储管理、分段存储管理、磁盘存储管理中涉及的地址转换问题。 虚拟地址与物理地址 编程一般只有可能和逻辑地址打交道,比如在 C 语言中&#x…...
HyperGBM用4记组合拳提升AutoML模型泛化能力
本文作者:杨健,九章云极 DataCanvas 主任架构师 如何有效提高模型的泛化能力,始终是机器学习领域的重要课题。经过大量的实践证明比较有效的方式包括: 利用Early Stopping防止过拟合通过正则化降低模型的复杂度使用更多的训练数…...
P6软件中的前锋线设置
卷首语 所谓前锋线,是指从评估时刻的时标点出发,用点划线一次连接各项活动的实际进展位置所形成的的线段,其通常为折线。 关键路径法 前锋线比较法,是通过在进度计划中绘制实际进度前锋线以判断活动实际进度与计划进度的偏差&a…...
Spring Boot + Vue3 前后端分离 实战 wiki 知识库系统<二>---后端架构完善与接口开发
数据库准备: 在上一次Spring Boot Vue3 前后端分离 实战 wiki 知识库系统<一>---Spring Boot项目搭建已经将SpringBoot相关的配置环境给搭建好了,接下来则需要为咱们的项目创建一个数据库。 1、mysql的安装: 关于mysql的安装这里就…...
如何在logback.xml中自定义动态属性
原文地址:http://blog.jboost.cn/trick-logback-prop.html 当使用logback来记录Web应用的日志时,我们通过在logback.xml中配置appender来指定日志输出格式及输出文件路径,这在一台主机或一个文件系统上部署单个实例没有问题,但是…...
嵌入式系统硬件设计与实践(第一步下载eda软件)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 现实生活中,我们经常发现有的人定了很多的目标,但是到最后一个都没有实现。这听上去有点奇怪,但确实是实实在在…...
Portraiture4免费磨皮插件支持PS/LR
Portraiture 4免去了繁琐的手工劳动,选择性的屏蔽和由像素的平滑,以帮助您实现卓越的肖像润色。智能平滑,并删除不完善之处,同时保持皮肤的纹理和其他重要肖像的细节,如头发,眉毛,睫毛等。 一键…...
Python学习笔记202302
1、numpy.empty 作用:根据给定的维度和数值类型返回一个新的数组,其元素不进行初始化。 用法:numpy.empty(shape, dtypefloat, order‘C’) 2、logging.debug 作用:Python 的日志记录工具,这个模块为应用与库实现了灵…...
2023年大数据面试开胃菜
1、kafka的message包括哪些信息一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成,header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成。当magic的值为1的时候,会在magic和crc32之间多一个字节…...
优雅的controller层设计
controller层设计 Controller 层逻辑 MVC架构下,我们的web工程结构会分为三层,自下而上是dao层,service层和controller层。controller层为控制层,主要处理外部请求。调用service层,一般情况下,contro…...
同步、通信、死锁
基础概念竞争资源引起两个问题死锁:因资源竞争陷入永远等待的状态饥饿:一个可运行程序由于其他进程总是优先于它,而被调用程序总是无限期地拖延而不能执行进程互斥:若干进程因相互争夺独占型资源而产生的竞争关系进程同步…...
【聚类】谱聚类解读、代码示例
【聚类】谱聚类详解、代码示例 文章目录【聚类】谱聚类详解、代码示例1. 介绍2. 方法解读2.1 先验知识2.1.1 无向权重图2.1.2 拉普拉斯矩阵2.2 构建图(第一步)2.2.1 ϵ\epsilonϵ 邻近法2.2.2 k 近邻法2.2.3 全连接法2.3 切图(第二步…...
最牛逼的垃圾回收期ZGC(1),简介
1丶什么是ZGC? ZGC是JDK 11中引入的一种可扩展的、低延迟的垃圾收集器。ZGC最主要的特点是:在非常短的时间内(一般不到10ms),就可以完成一次垃圾回收,而且这个时间是与堆的大小无关的。另外,ZGC支持非常大…...
微服务的Feign到底是什么
Feign是什么 分区是一种数据库优化技术,它可以将大表按照一定的规则分成多个小表,从而提高查询和维护的效率。在分区的过程中,数据库会将数据按照分区规则分配到不同的分区中,并且可以在分区中使用索引和其他优化技术来提高查询效…...
JavaScript 正则表达式
正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。搜索模式可用于文本搜索和文本替换。什么是正则表达式?正则表达式是由一…...
【批处理脚本】-1.15-文件内字符串查找命令find
"><--点击返回「批处理BAT从入门到精通」总目录--> 共7页精讲(列举了所有find的用法,图文并茂,通俗易懂) 在从事“嵌入式软件开发”和“Autosar工具开发软件”过程中,经常会在其集成开发环境IDE(CodeWarrior,S32K DS,Davinci,EB Tresos,ETAS…)中,…...
【手撕面试题】JavaScript(高频知识点二)
目录 面试官:请你谈谈JS的this指向问题 面试官:说一说call apply bind的作用和区别? 面试官:请你谈谈对事件委托的理解 面试官:说一说promise是什么与使用方法? 面试官:说一说跨域是什么&a…...
Web学习1_HTML
在学校期间学的Web知识忘了一些,很多东西摸棱两可,现重新系统的学习一下。 首先下载安装完vsc后并下载拓展文件live server(模拟一个服务器) Auto Rename Tag(在写网页时,自动对齐前后标签)在设…...
华为OD机试真题Java实现【靠谱的车】真题+解题思路+代码(20222023)
靠谱的车 题目 程序员小明打了一辆出租车去上班。出于职业敏感,他注意到这辆出租车的计费表有点问题,总是偏大。 出租车司机解释说他不喜欢数字4,所以改装了计费表,任何数字位置遇到数字4就直接跳过,其余功能都正常。 比如: 23再多一块钱就变为25; 39再多一块钱变…...
【C++入门(下篇)】C++引用,内联函数,auto关键字的学习
前言: 在上一期我们进行了C的初步认识,了解了一下基本的概念还学习了包括:命名空间,输入输出以及缺省参数等相关的知识。今天我们将进一步对C入门知识进行学习,主要还需要大家掌握我们接下来要学习的——引用…...
基于合作型Stackerlberg博弈的考虑差别定价和风险管理的微网运行策略研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
2023年全国最新保安员精选真题及答案8
百分百题库提供保安员考试试题、保安职业资格考试预测题、保安员考试真题、保安职业资格证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 81.以下各组情形都属于区域巡逻中异常情况的是()。 A&#x…...
JavaScript高级程序设计读书分享之6章——MapSet
JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 Map 作为 ECMAScript 6 的新增特性,Map 是一种新的集合类型,为这门语言带来了真正的键/值存储机制。Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在…...
西宁公司官方网站建设/推广普通话手抄报简单漂亮
#注册表操作# -*- coding: utf-8 -*- import win32api import win32con#打开注册表:传主键化值,子键值,操作方法(win32con.KEY_ALL_ACCESS、win32con.KEY_READ、win32con. KEY_WRITE) #返回句柄 def RegOpen(PKey,SKey…...
嘉兴网站制作套餐/互联网营销课程体系
基于CloudSim Plus的计算卸载仿真设计 1. 前提介绍 仿真框架的实现,主要依托于仿真实体、以及仿真事件,简单介绍如下 1.1 仿真实体 继承CloudSimEntity类(推荐)或者实现SimEntity接口(不建议) public class ExampleEntity extends CloudSimEntity {pu…...
wordpress微信缩略图/搜索引擎是软件还是网站
PHP语言是一个短生命周期的Web编程语言,很多PHPer已经形成了fpm下编程的思维定势。实际上在Swoole出现之后,这种串行化编程的模式早已被打破。使用Swoole完全可以轻易实现更灵活的并发编程。 场景介绍 假设我们要做一个石头剪刀布的Web游戏,…...
黄骅市领导班子最新调整/百度seo招聘
Java Enum原理 public enum Size{ SMALL, MEDIUM, LARGE, EXTRA_LARGE }; 实际上,这个声明定义的类型是一个类,它刚好有四个实例,在此尽量不要构造新对象。 因此,在比较两个枚举类型的值时,永远不需要调用equals方法&…...
万能网盘搜索引擎入口/seo专员是什么意思
最近想往数据库里导一些数据,同事推荐了mock,了解一下觉得不错,现将在vue用的mock贴上来 写在前默认看此文的盆友都是有vue基础的哟~~ 一、导读 将mockjs的数据直接展示在vue页面上 mockjs官网链接 二、安装mockJS //安装mockJS npm in…...
优化企业网站/百度一下打开
w10设置文件服务器 内容精选换一换华为云弹性文件服务(Scalable File Service)为用户的弹性云服务器(ECS)提供一个完全托管的共享文件存储,符合标准文件协议(NFS)来自:产品cd /home/ior-master/src/home/OpenMPI/bin/mpirun --allow-run-as-root -machin…...