JavaEE初阶——多线程(一)
此篇文章与大家分享多线程的第一部分:引入线程以及创建多线程的几种方式
此文章是建立在前一篇文章进程的基础上的
如果有不足的或者错误的请您指出!
1.认识线程
我们知道现代的cpu大多都是多核心的cpu,此时通过特定的编程技巧,即可以将不同的进程调度到多个cpu上执行,也就是我们在进程章节里面讲到的"并发".在我们的日常开发中,往往一个服务器要同时面对多个客户端,为多个客户端提供服务,此时如果只利用一个cpu处理客户端的请求,那么响应速度就会变慢.那么此时"多核心"的cpu就能起到一定的效果,每一个客户端连上服务器的时候,服务器都创建一个进程给客户端提供服务,客户端断开了,服务器就把进程销毁
但是随之而来的又是一个问题,服务器频繁的创建,销毁进程实际上也会对服务器的响应速度造成影响
我们引入多线程的初心就是为了解决上述"进程太重"的问题,线程实际上也称为"轻量级进程",顾名思义,他的创建和销毁开销都比进程要小
线程可以当成是进程的一部分,一个线程中可能含有一个线程,也可能含有多个线程
我们在进程章节谈到的进程,就是只针对一个进程里面只有一个线程而言的
我们在前面说过,描述一个进程是使用pcb这样的结构体,但是实际上准确来说应该是:一个pcb描述的是一个线程,多个pcb共同描述一个进程
那么我们对pcb中有些属性就该有新的认识
(1)pid :实际上一个线程对应的是一个pid,因此不同线程的pid是不一样的
(2)内存指针和文件描述操作符:在若干个线程中,这两个属性实际上是一样的
(3)状态、上下文、优先级、记账信息对应的是每个线程自己的属性
(4)tgid:在一个进程内是一样的,不同进程就不一样
此时,在同一个进程内,若干个线程之间的资源(内存资源和文件资源)是共享的,但是每个线程又是独立地在cpu上调度执行
因此就有一个重要的结论:进程是系统进行资源分配的基本单位,线程是系统调度执行的基本单位
(在进程章节谈到的进程调度,实际上就是线程调度)
为什么说线程比进程更轻量级??为什么说线程的创建和销毁比进程开销更小??
本质上就是因为创建进程的时候就要涉及到资源的分配,销毁进程的时候涉及到资源的销毁,而创建线程,由于同一个线程之间的资源是共享的,相当于资源已经有了,就省去了分配资源 / 销毁资源的步骤,只是在创建第一个线程(也就是创建进程的时候)需要这个步骤,因此线程自然就轻量
但是多线程就没有缺点嘛??
首先,一个进程内的线程不能无限地引入,引入的线程一旦多了,单位时间内要进行调度的次数也就增多了,此时对加大线程调度的开销,当这种开销太大的时候,实际上性能可能不升反降
其次,当多个线程同时访问和操作某写共享资源时,如多个线程并发地读取、修改、写入共享数据时,如果没有适当的同步措施,就可能会引发数据竞争等一系列的问题,就会让程序出现bug,这就是我们后面要谈到的线程安全问题
再者,如果一个线程出现问题,就可能会影响到其他线程,如某个线程如果抛出异常,但是没有很好地处理异常,就会使整个进程退退出
2.第一个多线程代码
2.1通过继承Thread来创建一个线程类
class MyThread extends Thread{@Overridepublic void run(){while(true){System.out.println("hello world");}}
}
public class Demo1 {public static void main(String[] args) {Thread t = new MyThread();thread.start();while(true){System.out.println("main");}}
}
(1)在MyThread中的run方法,就是用来描述这个线程具体要干什么活
(2)在上述代码中,实际上存在着两个线程,一个是我们main线程(也称主线程),一个是t线程,此时main线程和t线程就在并发式的执行了
我们可以通过java提供的工具:jconsole来清楚地看到不同的进程
至于剩下的线程,就是Jvm帮我们做的一些其他的工作,例如垃圾回收等
(5)可以利用sleep让线程进入阻塞状态
实际上就是让当前线程主动放弃去cpu上执行,时间到了线程才会解除阻塞状态,重新有机会被调度到cpu上执行
class MyThread extends Thread{@Overridepublic void run(){while(true){System.out.println("hello world");try {Thread.sleep(1000);//谁调用,谁就sleep} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread thread = new MyThread();thread.start();while(true){System.out.println("main");Thread.sleep(1000);}}
}
此时运行后可以明显发现打印速度变慢了
(6)在上面代码中,某一时刻先打印main还是Thread是不确定的,这是因为多个线程之间的调度顺序是"无序"的,在操作系统内部也称为抢占式执行.即任何一个线程在执行到任何一段代码的时候,都会被其他线程抢占了他的cpu资源,就会给别的线程执行,就会充满"随机性".也正是因为这样的随机性,导致我们很多程序的执行结果是"不可预估的",甚至可能带来bug
(7)关于start
我们前面说到到run方法,只是描述了一个线程具体应该干什么,而start方法才是操作系统提供的"创建线程"的api,此时调用start方法,在内核中才会真正创建一个pcb,真正为这个线程分配资源,进一步系统调度到这个线程的时候,才会执行到run方法
而如果我们直接执行run方法,那么就只是简单的执行run方法里面的代码逻辑,并没有创建一个线程
像这样创建一个方法(run),不去手动调用,而是交给系统 / 其他的库 / 其他的框架调用,就是回调函数
3.2通过实现runnable接口创建线程
class MyRunnable implements Runnable {@Overridepublic void run(){while(true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class Demo2 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new MyRunnable());t.start();System.out.println("hello main");}
}
Runnable的作用就只是描述了一个任务,这个任务与具体的执行机制无关,也就是我们是通过线程的方式执行还是通过其他的方式执行无所谓,这样的话就能把"任务"本身和"线程"概念分割开来了,这样的任务就可以交给其他地方来执行
对比刚刚的第一种方法,区别就是,刚刚第一种方法是线程自己记录我要干啥,而这种写法就是别人记录我要干啥,线程只是负责执行
这种方法方便代码的解耦合
3.3匿名内部类来实现
本质上就是上面两种,只不过换了一种方法来实现
public class Demo3 {public static void main(String[] args) {Thread thread = new Thread(){@Overridepublic void run() {....}};}
}
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while(true){System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}
3.5使用lambda表达式
public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{while(true){System.out.println("hello t");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();while(true){System.out.println("hello main");Thread.sleep(1000);}
}
我们会发现,用这种写法貌似没有重写run方法??
实际上lambda方法就是对run方法的实现,通过lambda这种方式,我们可以直接在Thread对象的构造函数中执行线程的任务逻辑,无需显示地重写run方法
感谢您的访问!!期待您的关注!!!
相关文章:

JavaEE初阶——多线程(一)
T04BF 👋专栏: 算法|JAVA|MySQL|C语言 🫵 小比特 大梦想 此篇文章与大家分享多线程的第一部分:引入线程以及创建多线程的几种方式 此文章是建立在前一篇文章进程的基础上的 如果有不足的或者错误的请您指出! 1.认识线程 我们知道现代的cpu大多都是多核心…...
MongoDB主从复制模式基于银河麒麟V10系统
MongoDB主从复制模式基于银河麒麟V10系统 背景介绍 MongoDB自4.0版本开始已经不再建议使用传统的master/slave复制架构,而是全面采用了复制集(Replica Sets)作为标准的复制和高可用性解决方案。 复制集是MongoDB的一种数据复制和高可用性机制,通过异步同步数据至多个服务…...

Vue使用高德地图
1.在高德平台注册账号 2.我的 > 管理管理中添加Key 3.安装依赖 npm i amap/amap-jsapi-loader --save 或 yarn add amap/amap-jsapi-loader --save 4.导入 AMapLoade import AMapLoader from amap/amap-jsapi-loader; 5.直接上代码,做好了注释(初始化…...
2024-04-07(复盘前端)
---HTML 1.HTMl骨架 html:整个网页 head:网页头部,用来存放给浏览器看的信息,如css body:网页主体,用来存放给用户看的信息,例如图片和文字 2.标题标签中h1标签只能使用一次,其…...

SpringCloud学习(10)-SpringCloudAlibaba-Nacos服务注册、配置中心
Spring Cloud Alibaba 参考文档 Spring Cloud Alibaba 参考文档 nacos下载Nacos 快速开始 直接进入bin包 运行cmd命令:startup.cmd -m standalone 运行成功后通过http://localhost:8848/nacos进入nacos可视化页面,账号密码默认都是nacos Nacos服务注…...
OKCC外呼中心配置的电话系统规则
OKCC外呼中心配置电话系统规则可能涉及多个方面,包括呼叫路由、自动化流程、电话接听策略等。以下是一般步骤及注意事项: 呼叫路由配置: 确定呼叫中心的呼叫路由策略,包括如何分配呼叫给不同的坐席或部门。设置呼叫路由规则&#…...
AI推介-大语言模型LLMs论文速览(arXiv方向):2024.03.31-2024.04.05
文章目录~ 1.AutoWebGLM: Bootstrap And Reinforce A Large Language Model-based Web Navigating Agent2.Training LLMs over Neurally Compressed Text3.Unveiling LLMs: The Evolution of Latent Representations in a Temporal Knowledge Graph4.Visualization-of-Thought …...
性能测试工具 ab(Apache Bench)使用详解
Apache Bench (ab) 是一个由 Apache 提供的非常流行的、简单的性能测试工具,用于对 HTTP 服务器进行压力测试。下面是 ab 工具的一些基本使用方法。 安装 在大多数 Unix 系统中,ab 通常作为 Apache HTTP 服务器的一部分预装在系统中。你可以通过在终端…...

智能网联汽车自动驾驶数据记录系统DSSAD数据元素
目录 第一章 数据元素分级 第二章 数据元素分类 第三章 数据元素基本信息表 表1 车辆及自动驾驶数据记录系统基本信息 表2 车辆状态及动态信息 表3 自动驾驶系统运行信息 表4 行车环境信息 表5 驾驶员操作及状态信息 第一章 数据元素分级 自动驾驶数据记录系统记录的数…...

Ubuntu 20.04.06 PCL C++学习记录(十八)
[TOC]PCL中点云分割模块的学习 学习背景 参考书籍:《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,,PCL版本为1.10.0,CMake版本为3.16 学习内容 PCL中实现欧式聚类提取。在点云处理中,聚类是一种常见的任务,它将点云数据划分为多…...

细雨踏春日,新会公安护平安
春雨起,清明至。又是一年春草绿,又是一年清明时。细雨踏春日,思怀故人时,是哀思,亦是相聚。新会公安一抹抹葵乡春日“警”色坚守岗位,确保清明祭扫平稳有序,为人民群众的平安保驾护航。 为确保2…...

3d怎么在一块模型上开个孔---模大狮模型网
在进行3D建模时,有时候需要在模型上创建孔,以实现特定的设计需求或功能。无论是为了添加细节,还是为了实现功能性的要求,创建孔都是常见的操作之一。本文将介绍在3D模型上创建孔的几种常用方法,帮助您轻松实现这一目标…...

Python景区票务人脸识别系统(V2.0),附源码
博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…...
全球化业务的网络安全挑战
随着企业业务的全球化,跨国数据传输和用户跨地域访问成为常态。这不仅带来了巨大的商业机会,也带来了以下网络安全挑战: 数据泄露风险:跨国数据传输增加了数据被截获和泄露的风险。访问限制:某些地区可能对互联网内容…...
SQL简单优化思路
在编写SQL查询时,优化查询性能是一个重要的考虑因素,特别是在处理多表连接(JOIN)和子查询时。以下是一些具体的技巧和最佳实践,可以帮助你在保持相同返回值的前提下,降低SQL执行速度: 明确连接顺…...

外包干了25天,技术倒退明显
先说情况,大专毕业,18年通过校招进入湖南某软件公司,干了接近6年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能…...

webpack环境配置分类结合vue使用
文件目录结构 按照目录结构创建好文件 控制台执行: npm install /config/webpack.common.jsconst path require(path) const {merge} require(webpack-merge) const {CleanWebpackPlugin} require(clean-webpack-plugin) const { VueLoaderPlugin } require(vue-loader); c…...

【蓝桥杯嵌入式】第十三届省赛(第二场)
目录 0 前言 1 展示 1.1 源码 1.2 演示视频 1.3 题目展示 2 CubeMX配置(第十三届省赛第二场真题) 2.1 设置下载线 2.2 HSE时钟设置 2.3 时钟树配置 2.4 生成代码设置 2.5 USART1 2.5.1 基本配置 2.5.2 NVIC 2.5.3 DMA 2.6 TIM 2.6.1 TIM2 2.6.2 TIM4 2.6.3 …...
maya节点绕轴旋转
目录 旋转后并尝试冻结变换 绕x轴旋转90度 使用Python脚本 使用图形界面 使用MEL脚本 绕y轴旋转90度 使用Python脚本 ok 旋转后并尝试冻结变换 import maya.cmds as cmdsdef adjust_root_rotation_for_export(joint_name):# 选择根节点cmds.select(joint_name)# 应用旋…...

如何水出第一篇SCI:SCI发刊历程,从0到1全过程经验分享!!!
如何水出第一篇SCI:SCI发刊历程,从0到1全路程经验分享!!! 详细的改进教程以及源码,戳这!戳这!!戳这!!!B站:Ai学术叫叫兽e…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...