多线程基础

线程与进程

进程

进程是对运⾏时程序的封装,是系统进⾏资源调度和分配的基本单位,实现了操作系统的并发。程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存(例如硬盘上有个程序叫QQ.exe,这是一个程序,当你双击它,登录进去了,这个时候叫做一个进程。进程相对于程序来说它是一个动态的概念)。

线程

线程是进程的⼦任务,是 CPU 调度和分派的基本单位,实现了进程内部的并发。线程本身基本上不拥有系统资源,只是拥有一些在运行时需要用到的系统资源,例如程序计数器,寄存器和栈等。一个进程中的所有线程可以共享进程中的所有资源。

多线程

多线程可以理解为在同一个程序中能够同时运行多个不同的线程来执行不同的任务,这些线程可以同时利用CPU的多个核心运行。多线程编程能够最大限度的利用CPU的资源。如果某一个线程的处理不需要占用CPU资源时(例如IO线程),可以使当前线程让出CPU资源来让其他线程能够获取到CPU资源,进而能够执行其他线程对应的任务,达到最大化利用CPU资源的目的。

进程与线程的区别

进程:有独立内存空间,每个进程中的数据空间都是独立的。

线程:多线程之间堆空间与方法区是共享的,但每个线程的栈空间、程序计数器是独立的,线程消

耗的资源比进程小的多。

并行与并发

并发(Concurrent):同一时间段,多个任务都在执行 ,单位时间内不⼀定同时执行。

并行(Parallel):单位时间内,多个任务同时执行,单位时间内一定是同时执行。并行上限取决

于CPU核数(CPU时间片内50ms)

注意:并发是一种能力,而并行是一种手段。当我们的系统拥有了并发的能力后,代码如果跑在多核

CPU上就可以并行运行。所以咱们会说高并发处理,而不会说高并行处理。并行处理是基于硬件CPU的

是固定的,而并发处理的能力是可以通过设计编码进行提高的。

什么是线程上下文切换

单核CPU内核,同一时刻只能被一个线程使用。为了提升CPU利用率,CPU采用了时间片算法将CPU时间片轮流分配给多个线程,每个线程分配了一个时间片(几十毫秒/线程),线程在时间片内,使用CPU执行任务。当时间片用完后,线程会被挂起,然后把 CPU 让给其它线程。

线程再次运行时,系统是怎么知道线程之前运行到哪里?

  • CPU切换前会把当前任务状态保存下来,用于下次切换回任务时再次加载。
  • 任务状态的保存及再加载的过程就叫做上下文切换。

任务状态信息保存在哪里呢?

  • 程序计数器:用来存储CPU正在执行的指令的位置,和即将执行的下一条指令的位置。
  • 他们都是CPU在运行任何任务前,必须依赖的环境,被叫做CPU上下文。

上下文切换过程:

  1. 挂起当前任务,将这个任务在 CPU 中的状态(上下文)存储于内存中的某处。
  2. 恢复一个任务,在内存中检索下一个任务的上下文并将在 CPU 的寄存器中恢复。
  3. 跳转到程序计数器所指定的位置(即跳转到任务被中断时的代码行)。

线程上下文切换会有什么问题呢?

过多的线程并行执行会导致CPU资源的争抢,产生频繁的上下文切换,常常表现为高并发执行时,RT延

长。因此,合理控制上下文切换次数,可以提高多线程应用的运行效率。(也就是说线程并不是越多越

好,要合理的控制线程的数量。)

直接消耗:指的是CPU寄存器需要保存和加载,系统调度器的代码需要执行

间接消耗:指的是多核的cache之间得共享数据,间接消耗对于程序的影响要看线程工作区操作数

据的大小。

线程的创建方式

在Java中,实现线程的方式大体上分为三种,通过继承Thread类、实现Runnable接口,实现Callable接口。

继承Thread类
public class ThreadStyle extends Thread{@Overridepublic void run() {System.out.println("用Thread类实现线程");}public static void main(String[] args) {new ThreadStyle().start();}
}
实现 Runnable 接⼝
public class RunnableStyle implements Runnable{public static void main(String[] args) {Thread thread = new Thread(new RunnableStyle());thread.start();}@Overridepublic void run() {System.out.println("用Runnable方法实现线程");}
}
实现 Callable 接⼝
public class CallableStyle implements Callable<String> {@Overridepublic String call() throws Exception {return "Hello, calling";}public static void main(String[] args) {//创建异步任务FutureTask<String> task = new FutureTask<String>(new CallableStyle());//启动线程new Thread(task).start();try {//等待执⾏完成,并获取返回结果String result = task.get();System.out.println(result);} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}
}

线程的生命周期

在操作系统中,线程被视为轻量级的进程,所以线程状态其实和进程状态是⼀致的。

查看Thread源码,能够看到java的线程有六种状态:

public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED;
}

线程的生命周期可以总结为下图:

New

处于 NEW 状态的线程此时尚未启动。这⾥的尚未启动指的是还没调⽤ Thread 实例的 start() ⽅法。

public class StateThreadNew {public static void main(String[] args) {Thread thread = new Thread(() -> {});System.out.println(thread.getState()); // 输出 NEW}
}
public class NewRunnableTerminated implements Runnable{public static void main(String[] args) {Thread thread = new Thread(new NewRunnableTerminated());//打印出New状态System.out.println(thread.getState());thread.start();System.out.println(thread.getState());try {Thread.sleep(100);}catch (InterruptedException e) {e.printStackTrace();}//打印出Runnable的状态,即使是正在运行,也是Runnable,而不是Running//如果休眠100秒是terminated状态System.out.println(thread.getState());}@Overridepublic void run() {for (int i = 0; i< 1000; i++) {System.out.println(i);}}
}

从上⾯可以看出,只是创建了线程⽽并没有调⽤ start ⽅法,此时线程处于 NEW 状态。

RUNNABLE

可运行状态,可运行状态可以包括:运行中状态和就绪状态。

BLOCKED

阻塞状态,处于这个状态的线程需要等待其他线程释放锁或者等待进入synchronized。

WAITING

表示等待状态,处于该状态的线程需要等待其他线程对其进行通知或中断等操作,进而进入下一个状态。

调⽤下⾯这 3 个⽅法会使线程进⼊等待状态:

Object.wait() :使当前线程处于等待状态直到另⼀个线程唤醒它;

Thread.join() :等待线程执⾏完毕,底层调⽤的是 Object 的 wait ⽅法;

LockSupport.park() :除⾮获得调⽤许可,否则禁⽤当前线程进⾏线程调度。

TIME_WAITING

超时等待状态。可以在一定的时间自行返回。

调⽤如下⽅法会使线程进⼊超时等待状态:

Thread.sleep(long millis) :使当前线程睡眠指定时间;

Object.wait(long timeout) :线程休眠指定时间,等待期间可以通过 notify() / notifyAll() 唤醒;

Thread.join(long millis) :等待当前线程最多执⾏ millis 毫秒,如果 millis 为 0,则会⼀直执⾏;

LockSupport.parkNanos(long nanos) : 除⾮获得调⽤许可,否则禁⽤当前线程进⾏线程调度指定时

间;LockSupport 我们在后⾯会细讲;

LockSupport.parkUntil(long deadline) :同上,也是禁⽌线程进⾏调度指定时间;

TERMINATED

终止状态,当前线程执行完毕。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/253832.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Arthas使用教程—— 阿里开源线上监控诊断产品

文章目录 1 简介2背景3 图形界面工具 arthas 阿里开源3.1 &#xff1a;启动 arthas3.2 help :查看arthas所有命令3.3 查看 dashboard3.4 thread 列出当前进程所有线程占用CPU和内存情况3.5 jvm 查看该进程的各项参数 &#xff08;类比 jinfo&#xff09;3.6 通过 jad 来反编译 …

2-1 动手学深度学习v2-Softmax回归-笔记

回归 VS 分类 回归估计一个连续值分类预测一个离散类别 从回归到多类分类 回归 单连续数值输出输出的区间&#xff1a;自然区间 R \mathbb{R} R损失&#xff1a;跟真实值的区别 分类 通常多个输出&#xff08;这个输出的个数是等于类别的个数&#xff09;输出的第 i i i…

Flink Format系列(2)-CSV

Flink的csv格式支持读和写csv格式的数据&#xff0c;只需要指定 format csv&#xff0c;下面以kafka为例。 CREATE TABLE user_behavior (user_id BIGINT,item_id BIGINT,category_id BIGINT,behavior STRING,ts TIMESTAMP(3) ) WITH (connector kafka,topic user_behavior…

机器学习——有监督学习和无监督学习

有监督学习 简单来说&#xff0c;就是人教会计算机学会做一件事。 给算法一个数据集&#xff0c;其中数据集中包含了正确答案&#xff0c;根据这个数据集&#xff0c;可以对额外的数据希望得到一个正确判断&#xff08;详见下面的例子&#xff09; 回归问题 例如现在有一个…

17:定时器编程实战

1、实验目的 (1)使用定时器来完成LED闪烁 (2)原来实现闪烁时中间的延迟是用delay函数实现的&#xff0c;在delay的过程中CPU要一直耗在这里不能去做别的事情。这是之前的缺点 (3)本节用定时器来定一个时间&#xff08;譬如0.3s&#xff09;&#xff0c;在这个定时器定时时间内…

Visual Studio 2022中创建的C++项目无法使用万能头<bits/stdc++.h>解决方案

目录 发现问题 解决办法 第一步 第二步 第三步 第四步 最后一步 问题解决 发现问题 如果大家也遇到下面这种问题&#xff0c;可能是没有include文件夹中没有bits/stdc.h 解决办法 第一步 打开一个C项目&#xff0c;鼠标移动至头文件上右击&#xff0c;选择转到文档或…

嵌入式学习之Linux入门篇笔记——10,Linux连接档概念

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 目录 1.Linux 下的连接档种类 2.什么是 inode&#xff1f; 3.什…

【HarmonyOS应用开发】HTTP数据请求(十四)

文章末尾含相关内容源代码 一、概述 日常生活中我们使用应用程序看新闻、发送消息等&#xff0c;都需要连接到互联网&#xff0c;从服务端获取数据。例如&#xff0c;新闻应用可以从新闻服务器中获取最新的热点新闻&#xff0c;从而给用户打造更加丰富、更加实用的体验。 那么…

支持534种语言,开源大语言模型MaLA-500

无论是开源的LLaMA 2还是闭源的GPT系列模型&#xff0c;功能虽然很强大&#xff0c;但对语言的支持和扩展比较差&#xff0c;例如&#xff0c;二者都是以英语为主的大模型。 为了提升大模型语言的多元化&#xff0c;慕尼黑大学、赫尔辛基大学等研究人员联合开源了&#xff0c;…

Windows 安装 MySQL 最新最简教程

Windows 安装 MySQL 最新最简教程 官网地址 https://dev.mysql.com/downloads/mysql/下载 MySQL zip 文件 配置 MySQL1、解压文件 2、进入 bin 目录 搜索栏输入 cmd 回车进入命令行 C:\Users\zhong\Desktop\MySQL\mysql-8.3.0-winx64\mysql-8.3.0-winx64\bin 注意这里是你自己…

Java图形化界面编程——Container容器 笔记

2.3 Container容器 2.3.1 Container继承体系 Winow是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;Panel可以容纳其他组件&#xff0c;但不能独立存在&#xff0c;它必须内嵌其他容器中使用&#xff0c;默认使用FlowLayout管理其内部组件布局&#xff1b;S…

物理信息神经网络(PINN): 将物理知识融合到深度学习中

物理信息神经网络&#xff08;PINN&#xff09;: 将物理知识融合到深度学习中 物理信息神经网络&#xff08;PINN&#xff09;简介PINN的工作原理PINN模型如何利用物理法则指导模型训练1. 定义物理问题和相应的物理定律2. 构建神经网络3. 定义损失函数数据误差项 (Data-fidelit…

Flask 入门6:模板继承

1. 一个网站中&#xff0c;大部分网页的模块是重复的&#xff0c;比如顶部的导航栏&#xff0c;底部的备案信息。如果在每个页面中都重复的去写这些代码&#xff0c;会让项目变得臃肿&#xff0c;提高后期的维护成本。比较好的做法是&#xff0c;通过模板继承&#xff0c;把一…

Netty中使用编解码器框架

目录 什么是编解码器&#xff1f; 解码器 将字节解码为消息 将一种消息类型解码为另一种 TooLongFrameException 编码器 将消息编码为字节 将消息编码为消息 编解码器类 通过http协议实现SSL/TLS和Web服务 什么是编解码器&#xff1f; 每个网络应用程序都必须定义如何…

解决CORS错误(Spring Boot)

记录一下错误&#xff0c;以博客的形式 前言 跨域&#xff08;Cross-Origin&#xff09;是指在Web开发中&#xff0c;当一个Web应用试图从一个源&#xff08;域名、协议、端口组合&#xff09;获取资源时&#xff0c;该请求的目标与当前页面的源不同。具体来说&#xff0c;当一…

25、数据结构/二叉树相关练习20240207

一、二叉树相关练习 请编程实现二叉树的操作 1.二叉树的创建 2.二叉树的先序遍历 3.二叉树的中序遍历 4.二叉树的后序遍历 5.二叉树各个节点度的个数 6.二叉树的深度 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h> ty…

SolidWorks学习笔记——入门知识2

目录 建出第一个模型 1、建立草图 2、选取中心线 3、草图绘制 4、拉伸 特征的显示与隐藏 改变特征名称 5、外观 6、渲染 建出第一个模型 1、建立草图 图1 建立草图 按需要选择基准面。 2、选取中心线 图2 选取中心线 3、草图绘制 以对称图形举例&#xff0c;先画出…

蓝桥杯---生日蜡烛

某君从某年开始每年都举办一次生日party&#xff0c;并且每次都要吹熄与年龄相同根数的蜡烛&#xff0c;现在算起来&#xff0c;他一共吹熄了236根蜡烛。请问,他从多少岁开始过生日party的? 请填写他开始过生日 party的年龄数。 注意:你提交的应该是一个整数&#xff0c;不要…

路由器如何映射端口映射?

在现代互联网中&#xff0c;随着网络应用的不断发展&#xff0c;很多用户需要进行远程访问或搭建服务器来满足自己的需求。由于网络安全的原因&#xff0c;直接将内网设备暴露在公网中是非常危险的。为了解决这个问题&#xff0c;路由器映射端口映射技术应运而生。本文将介绍什…

redis之布隆过滤

目录 1、redis之布隆过滤 2、布隆过滤器原理 3、布隆过滤器使用步骤 初始化bitmap 添加占坑位 判断是否存在圜 1、redis之布隆过滤 布隆过滤&#xff1a;有一个初值都为0的bit数组和多个哈希函数构成&#xff0c;用来快速判断集合中是否存在某个元素。目的&#xff1a;减…