【JavaEE】浅谈线程(一)
线程
- 前言
- 线程的由来
- 线程是什么
- 线程的属性
- 线程更高效的原因
- 举个例子(线程便利性的体现)
- 多线程代码
- 线程并发执行的代码
- jconsole(观测多线程)
- 线程的调度问题
- 创建线程的几种方法
- 1)通过继承Thread 重写run
- 2)使用Runnable接口 重写run 有利于解耦合
- 3)匿名内部类
- 4)Runnable匿名内部类
- 5)Lambda表达式
- 总结
前言
线程的由来
现如今的CPU存在多个核心,因此能够同时处理多个进程,我们也称为并发执行(并行+并发)。通过这样的“多进程模式”,能够很好的利用多核CPU,极大的提升了效率。
但是,多进程的编程虽然好用,但也会带来一些问题。
在服务器中,需要给多个客户端提供服务,如果同时来了多个客户端,如此一来,只能用多个进程处理这件事情。这样会导致服务器频繁进行创建+销毁进程的操作,这是极其影响效率的。
于是引入了"轻量级进程"——线程。线程的创建和开销会小的多。
线程是什么
线程,可以理解为“线程的一部分”;一个进程中可以包含多个线程。
在进程中存在PCB结构体,一个PCB代表着一个线程,而一个进程由多个PCB构成,若干个PCB联合在一起,描述了一个进程。举个例子来说:进程像是一个小区,而线程就是一个个住在小区里的人。
线程的属性
因为线程存在与进程中,因此他们共用一个PCB,为了区分线程之间的区别,设置了一个新的概念词tgid(tgd)。同一个进程的tgid是相同的而pid是不同的;线程们共用同一份内存指针和文件描述符表。
因为线程们共用内存资源和文件资源的原因,线程之间可以访问到彼此的数据。而每个线程都是在独立的CPU上调度执行。因此我们可以认为:线程是系统调度执行的基本单位,进程是系统资源分配的基本单位。
线程更高效的原因
进程在创建和销毁过程中需要进行资源分配和资源释放的过程,而线程存在于进程中,线程之间共用资源,在线程创建和销毁的过程中可以省略资源分配/释放的步骤,省去了申请资源的过程,因此线程是更高效,更轻量级的一种进程。
举个例子(线程便利性的体现)
现在有一项任务需要完成,我们可以选择创建一个进程来解决,如果这个任务太繁重了,我们可以选择创建多个进程来分担压力。这种方法好是好,但是进程的创建和销毁会占用到资源,造成资源的浪费。
但是现在,我们学过线程了!我们可以选择在进程中创建多个线程,同时通过多核CPU的特点让线程可以达到并发执行的效果,这样既不会有申请资源的烦恼,又能高速高效的执行任务,可谓是一举多得!(鼓掌)
当然说归说,我们不能想到这么方便,直接在进程中创建多个线程叠罗汉不就好了,这肯定是不对的。俗话说的好:物极必反。如果我们一味的引入,自然会引发其他的问题(且听下回分解)
多线程代码
在JVM中已经对线程封装好了,即Thread类。我们可以通过Thread类实现线程的创建。接下来我写一份简单的代码进行演示
class MyThread extends Thread {@Overridepublic void run() {System.out.println("hello thread");}
}
public class ThreadDemo1{public static void main(String[] args) {Thread t = new MyThread();t.start();}
}
如何理解这段代码呢?首先创建了MyThread类并继承Thread方法,实现动态绑定。接着重写Thread的run方法;run()方法中包含的是线程t要执行的方法;而t.start()方法是启动线程t的方法。这段代码中有两个线程:t线程和main线程。由此我们可以知道,在学习线程之前的代码中,只存在着一个线程:main线程。同时我们也称main线程为主线程。
当然,run()是start()创建出来的线程,在线程里被调用的,run()方法已经创建好而不去手动调用,将这个方法交给系统/其他的库调用,即“回调函数”。
线程并发执行的代码
或许在上面的代码中我们不能很好的看出来t线程和main线程是怎么体现并发执行的,因此这边我分别在两个线程中加入两个循环以求更好的体现出线程并发执行的特点。
class MyThread extends Thread {@Overridepublic void run() {while (true){System.out.println("hello thread");}}
}
public class ThreadDemo1{public static void main(String[] args) {Thread t = new MyThread();t.start();while (true){System.out.println("hello main");}}
}
在这里我们也看到了 “hello thread” 和 "hello main"线程在控制台上交替打印,这也代表着两个线程正在并发执行。
jconsole(观测多线程)
jconsole是java的一款观测线程的实用工具,我已在其他文章中编写好,需要的可以观看下面的文章。
jconsole的简单使用
线程的调度问题
在上面的线程循环代码中我们已经可以证明多线程是并发执行的。
那么他们执行的顺序是否存在规律呢?
我们可以使用Thread.sleep()方法进行简单的观测。
Thread.sleep()可以设置时间使线程停止接下来的工作,使线程进入休眠状态(阻塞)。在规定的时间过后线程继续运行,执行未完成的任务。
代码如下
class MyThread extends Thread {@Overridepublic void run() {while (true){System.out.println("hello thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo1{public static void main(String[] args) {Thread t = new MyThread();t.start();while (true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
部分运行结果如下:
从这部分运行结果我们可以看出来,线程的运行使无序的。在操作系统中也称之为**“抢占式执行”。任何一个线程,在执行到任何一个代码的过程中,都可能被其他的线程抢占掉它的cpu资源,于是cpu就给别的线程执行了。
如果是这样的结果,显然这样的抢占式执行充满了随机性,执行效果难以预测甚至可能引入bug。**这肯定是程序猿们不想看到的,这涉及到了线程的安全问题。
创建线程的几种方法
1)通过继承Thread 重写run
在上面的代码中已经展示,这边不再赘述。
2)使用Runnable接口 重写run 有利于解耦合
在Runnable接口中,我们可以通过查看源码看到,其中只有一个抽象类方法run(),因此Runnable的作用就是描述一个任务,一个行为。**无论是线程还是其他方法执行run()这个方法都是可以的**。
通过Runnable方法实现的多线程有一个好处:解耦合。
在第一种写法中,线程重写自己的run()方法,以及线程调用的都是自己本身的方法;而使用Runnable方法之后,在后续进行代码的改动将会降低成本。
下面给出一个举例
class MyRunnable implements Runnable{@Overridepublic void run() {while (true){System.out.println("hello runnable");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
public class ThreadDemo2{public static void main(String[] args) {Thread t = new Thread(new MyRunnable());t.start();while (true){System.out.println("hello main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
3)匿名内部类
继承Thread 重写run,创建Thread的子类(不知名),同时也创建了一个不具名子类实例。我们看看下面的代码:
public class ThreadDemo3{public static void main(String[] args) {Thread t1 = new Thread(){@Overridepublic void run() {System.out.println("使用匿名内部类");}};t1.start();}
}
4)Runnable匿名内部类
与Thread匿名内部类的写法类似,在new Runnable之后直接重写Runnable的方法,这也创建了一个实例(不知名)实现了Runnable接口的方法。
演示代码如下:
public class ThreadDemo4 {public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("匿名内部类使用Runnable");}});t1.start();System.out.println("hello main");}
}
5)Lambda表达式
通过使用lambda表达式代替需要重写的run方法。
public class ThreadDemo5 {//lambda表达式//lambda本质上也是一个匿名函数,用完就丢public static void main(String[] args) {Thread t = new Thread(() ->{while (true){System.out.println("hello thread");}});t.start();System.out.println("hello main");}
}
总结
线程是一个轻量级进程,能够很大程度上节约成本和资源,在开发中有着十分重要的作用。同样的,引入多线程意味着我们需要解决一些引入所带来的问题。(如线程安全问题)这是随着我们逐渐深入了解所需要做的。
需要源码的可以点击链接:线程代码
有帮助到大家的请三连~感谢!!
相关文章:

【JavaEE】浅谈线程(一)
线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子(线程便利性的体现) 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1)通过继承Thread 重写run2)使用Runnable接口 重写ru…...

深度解析SPARK的基本概念
关联阅读博客文章: 深入理解MapReduce:从Map到Reduce的工作原理解析 引言: 在当今大数据时代,数据处理和分析成为了企业发展的重要驱动力。Apache Spark作为一个快速、通用的大数据处理引擎,受到了广泛的关注和应用。…...

FreeGPT3.5 开源软件
GPT-3.5不需要付费,也不需要注册用户,可以直接使用了,官方彻底开放了API接口。 该API政策一放开,GitHub很快就已经出现了一个开源项目FreeGPT35,可以自动生成key调用GPT3.5的API接口,再也用不着注册账号和申…...

AI绘本生成解决方案,快速生成高质量的AI绘本视频
美摄科技凭借其深厚的技术积累和前瞻性的市场洞察力,近日推出了一款面向企业的AI绘本生成解决方案,旨在通过智能化、自动化的方式,帮助企业快速将文字内容转化为生动有趣的绘本视频,从而提升内容传播效率,增强品牌影响…...

RabbitMQ3.13.x之九_Docker中安装RabbitMQ
RabbitMQ3.13.x之_Docker中安装RabbitMQ 文章目录 RabbitMQ3.13.x之_Docker中安装RabbitMQ1. 官网2. 安装1 .拉取镜像2. 运行容器 3. 访问 1. 官网 rabbitmq - Official Image | Docker Hub 2. 安装 1 .拉取镜像 docker pull rabbitmq:3.13.0-management2. 运行容器 # lates…...

【操作系统】STM32-操作系统——持续更新
【操作系统】STM32-操作系统——持续更新 文章目录 前言一、ucosii二、freertos1.介绍2.移植 总结 前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、ucosii UCOSII移植到STM32F103C8T6上之移植记录(一) UCOSII移植到ST…...

Redux Toolkit+TypeScript最佳实践
Redux-Toolkit是为了简化使用Redux繁琐的步骤,可以j降低使用useReducer与useContext管理状态的频率,而且起到项目中状态管理规范和约束化的效果。 阅读本文需要的前置知识:React、Redux、Typescript、Redux hooks。 Redux-Toolkit使用步骤 …...

假期别闲着:REST API实战演练之创建Rest API
1、创建实体类,模拟实体对象 创建一个类,模拟数据数据库来存储数据,这个类就叫Person。 其代码如下: package com.restful;public class Person {private String name;private String about;private int birthYear;public Perso…...

C++模仿qq界面
#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口的大小this->resize(645,497);//设置窗口名字this->setWindowTitle("QQ");//设置窗口图标this->setWindowIcon(QIcon("C:\\zhouzhouMyfile\\qt_proj…...

3D模型在线轻量化工具
在计算机图形学领域,3D模型简化工具是一种强大的工具,用于减少模型的面数,以提高模型在渲染和处理过程中的性能。本文将全面介绍为何需要简化模型、简化的方法、常见的简化算法以及一款三维模型优化产品 的使用方法,帮助读者更好地…...

去中心化社交媒体:分析 Facebook 在区块链平台上的角色
在当今数字时代,社交媒体已经成为人们日常生活中不可或缺的一部分。然而,随着人们对数据隐私和信息控制的关注不断增加,传统的中心化社交媒体平台也面临着越来越多的质疑和挑战。为了应对这些挑战,越来越多的人开始探索去中心化社…...

实现多租户JAVA支付(微信拉起支付):一个简单而强大的解决方案
简介: 本篇文章为多租户场景 在当今数字经济时代,许多企业都面临着处理多租户支付的挑战。多租户系统是指一种架构,其中单个实例的软件服务多个租户,每个租户的数据通常被隔离,以确保安全性和数据隐私。而在这种环境…...

万字长文:FineBI面试题及参考答案详解
1:FineBI的基本概念是什么? FineBI是帆软软件有限公司推出的一款商业智能产品。它的核心功能是通过分析企业已有的信息化数据,帮助企业发现并解决存在的问题,预测模拟企业将来的发展,并协助企业及时调整策略做出更好的决策,增强企业的可持续竞争性。 2:描述FineBI的使…...

Python爬虫:为什么你爬取不到网页数据
目录 前言 一、网络请求被拒绝 二、数据是通过JavaScript加载的 三、需要进行登录 四、网站反爬虫策略 五、网站结构变更 总结 前言 作为一名开发者,使用Python编写爬虫程序是一项常见的任务。爬虫程序的目的是收集互联网上的数据,并将其保存或使…...

NLP在搜索召回领域中的应用场景
自然语言处理(NLP)在搜索召回领域中的应用场景非常广泛,它通过理解和分析人类语言,提高了信息检索的准确性和效率。以下是一些具体的应用场景: 1. 搜索引擎优化 NLP技术可以用于优化搜索引擎的查询处理,通…...

2. Django配置信息
第2章 Django配置信息 Django的配置文件settings.py用于配置整个网站的环境和功能, 核心配置必须有项目路径, 密钥配置, 域名访问权限, App列表, 中间件, 资源文件, 模板配置, 数据库的连接方式.* 项目运行时, 如果修改代码, 项目会自动检测发现改动后会重新运行, 除非报错否…...

【Web】纯萌新的BUUCTF刷题日记Day1
目录 [RoarCTF 2019]Easy Java [网鼎杯 2018]Fakebook [CISCN2019 华北赛区 Day2 Web1]Hack World [BJDCTF2020]The mystery of ip [网鼎杯 2020 朱雀组]phpweb [BSidesCF 2020]Had a bad day [BJDCTF2020]ZJCTF,不过如此 [BUUCTF 2018]Online Tool [GXYCTF…...

【51单片机入门记录】RTC(实时时钟)-DS1302概述
目录 一、基于三线通信的RTC-DS1302 (1)简介 (2)特性 (3)引脚介绍 (4)控制字的格式 (5.0)日历时钟寄存器介绍 (5.1)日历时钟寄存…...

Lua热更新(AssetBundle)
AssetBundle 新版本导入ab包报错,则删除其中的Tests文件夹。 给资源分组 打包设置:平台、路径、重复打包清空文件夹、复制到streaming文件夹 建议勾选 建议使用LZ4压缩方式 用来观察文件中的包大小,不常用 参数总结: 这六个只做了解,重要的是上面的...

互联网人才现状分析
作者:哈哥撩编程(视频号、抖音、公众号同名) 新星计划全栈领域优秀创作者博客专家全国博客之星第四名超级个体COC上海社区主理人特约讲师谷歌亚马逊演讲嘉宾科技博主极星会首批签约作者 🏆 推荐专栏: 🏅…...

高级IO——多路转接
高级IO——五种IO模型 首先我们之前在基础IO部分就学过IO的过程分等待过程和读写过程! 比如我们的scanf除了从键盘缓冲区读取数据所花的时间,主要的时间花费放在了等你输入的过程! 所以我们如果想提高我们的IO效率,我们除了要缩…...

TypeScript常用知识点整理
介绍 TypeScript 是 JavaScript 的一个超集,添加了静态类型支持和更多现代编程特性,提高了代码的可靠性和可维护性。最终会被编译成标准的 JavaScript 代码运行。 使用npm install -g typescript进行全局安装 将编写好的ts代码进行运行,第…...

【Unity实战100例】Unity入门小地图位置同步(第一第三人称)
unity小地图制作包括第一人称控制器和第三人称控制器 目录 一.选择合适自身的人称控制器 二.小地图制作...

蓝桥杯简单模板
目录 最大公约数 两个数的最大公约数 多个数的最大公约数 最小公倍数 两个数的最小公倍数 多个数的最小公倍数 素数 编辑 位数分离 正写 编辑 反写 闰年 最大公约数 两个数的最大公约数 之前看见的是辗转相除法,例如现在让算一个49,21…...

单例模式(饿汉模型,懒汉模型)
在着里我们先了解什么是单例模式。 就是某个类在进程中只能有单个实例,这里的单例模式需要一定的编程技巧,做出限制,一旦程序写的有问题,创建了多个实例,编程就会报错。 如果我们学会了单例模式,这种模式…...

torchvision中的数据集使用
torchvision中的数据集使用 使用和下载CIFAR10数据集 输出测试集中的第一个元素(输出img信息和target) 查看分类classes 打断点–>右键Debug–>找到classes 代码 import torchvisiontrain_set torchvision.datasets.CIFAR10(root"./data…...

linux 迁移home目录以及修改conda中pip的目录,修改pip安装路径
1)sudo rsync -av /home/lrf /data/home/lrf 将/home目录下的文件进行复制(假设机械硬盘挂载在/data目录下)** 2)usermod -d /data/home/lrf -m lrf 修改用户$HOME变量** 3)vi /etc/passwd 查看对应用户的$HOME变量是…...

解析大语言模型训练三阶段
大语言模型的训练过程一般包括3个阶段:预训练(Pre-training)、SFT(有监督的微调,Supervised-Finetuning)以及RLHF(基于人类反馈的强化学习,Reinforcement Learning from Human Feedb…...

知识图谱的最新进展与未来趋势
知识图谱的最新进展与未来趋势 一、引言 在过去的几年中,知识图谱已经从一个前沿的研究概念发展成为现代信息技术不可或缺的一部分。作为结构化知识的存储和表示形式,知识图谱通过组织信息和数据提供了深刻的洞见,它已被广泛应用于搜索引擎优…...

Facebook直播延迟过高是为什么?
在进行Facebook直播 时,高延迟可能会成为一个显著的问题,影响观众的观看体验和互动效果。以下是一些导致Facebook直播延迟过高的可能原因: 1、网络连接问题 网络连接不稳定或带宽不足可能是导致Facebook直播延迟的主要原因之一。如果您的网络…...