多线程编程1

一、线程的引入

上节,我们介绍了进程的概念,以及操作系统内核是如何管理进程的(描述+组织),PCB中的核心属性有哪些,

引入进程这个概念,最主要的目的,就是为了解决“并发编程”这样的问题。

为什么我们需要并发编程?

这是因为CPU进入了多核心时代,为了进一步提高程序的执行速度,就需要充分利用CPU的多核资源这就需要“并发编程”。

多进程编程让大量进程可以在多个CPU核心上运行,程序代码已经能够把CPU的多核资源利用起来了,已经可以解决“并发编程”的问题了。

我们为什么又要学习多线程编程呢?

线程又是什么呢?和进程又有什么关系?

带着这些疑问,我慢慢进行介绍。

二、线程和进程的关系

(1)进程包含线程。一个进程可以包含一个线程,也可以包含多个线程。进程中至少有一个线程,不能没有。

(2)一个线程是通过一个PCB来描述的,PCB对应的是线程,一个线程对应一个PCB,一个进程对应1个或多个PCB。

(3)进程是操作系统资源分配的基本单位,线程是操作系统调度执行的基本单位。同一进程里的多个线程之间共享进程资源。

PCB中的核心属性:pid、内存指针、文件描述符表,这些是进程中的线程共用的处于同一个进程中的线程,pid相同,内存指针和文件描述符表也是一样的。

PCB中与调度相关的属性:状态、优先级、上下文、记账信息,是每个线程自己有自己的,各自记录各自的。

对于第三点,我再啰嗦几句,希望能加深大家的理解:

同一个进程里的多个线程之间,共用了进程的同一份资源这里共用的资源主要指的是内存指针和文件描述符表。比如:线程1里new的对象,在线程2,3,4里都可以直接使用(共用内存指针),线程1打开的文件,在线程2,3,4里都可以直接使用(共用文件描述符表)。

操作系统,实际调度的时候,以线程为单位进行调度的。并不关系进程,只关心线程。谈到调度,就和进程无关了!!上节提到的进程调度,指的是这里的进程只包含一个线程的情况。如果进程中有多个线程,那么每个线程是独立在CPU上调度的。比如,线程1可能在核心A上执行,线程2可能在核心B上执行。线程是操作系统调度执行的基本单位。每个线程都有自己的执行逻辑,我们称为执行流。

三、为什么要使用多线程编程?

多进程和多线程都可以解决并发编程问题,为什么更倾向于使用多线程编程呢?

因为,

进程,太“重”了。创建/销毁/调度一个进程,都需要很大的资源消耗,速度慢。

线程,又叫“轻量级进程”。创建/销毁/调度一个线程,消耗资源少,速度快。

使用多线程编程,会提高效率。

为什么线程比较“轻”?

因为只有在创建第一个线程时,操作系统会进行资源分配(主要指内存指针,文件描述符表),之后创建的第2,3,4...个线程,复用之前的分配的资源,基本不需要操作系统再分配资源。销毁一个线程,也基本不需要释放资源。除非这个进程中只有这一个线程了,才需要释放资源。

而进程就不一样了,创建一个进程,操作系统会进行资源分配,销毁一个进程,要释放资源。创建第二个进程,还需要申请资源,销毁第二个进进程,同样需要释放资源。消耗资源多,速度慢。

因此,由于进程和线程各自的特点,我们一般使用多线程编程,减少资源消耗,提高速度。

四、线程越多越好?多线程会有安全问题吗?

增加线程数量并不是可以一直提高速度。 CPU的核心数量是有限的。线程太多,核心数目有限,不少的开销反而浪费在线程调度上。所以,并不是线程越多越好。

多线程容易出现线程安全问题。

(1)多线程中,共享同一份资源,可能会出现多个线程同时都需要同一个资源的现象(如同一个变量),出现争抢

(2)如果一个线程抛异常,处理不好的话,可能会把整个进程都带走,其它线程也就挂了。

什么时候会出现安全问题多个执行流访问同一个共享资源的时候。

线程模型,天然就是资源共享的,多线程争抢同一个资源(如同一个变量)非常容易触发。

进程模型,天然就是资源隔离的,不容易触发。只有进行进程间通信时,多个进程访问同一个资源,这时才可能会出问题。

也就是说,多线程会提高效率,但是不如多进程安全。当然,代码写的靠谱,线程安全问题也不怕

五、在Java中如何进行多线程编程?

操作系统提供了操作线程的一系列API。

而Java是一个跨平台的语言,很多操作系统提供的功能,都被JVM给封装好了。我们不需要学习操作系统提供的原生API,只需要学习Java提供的API就行啦

Java操作多线程,最核心的类是Thread(在java.lang下,不用import)

创建线程,是希望线程成为一个独立的执行流,能执行一段代码。我们可以这样理解,

创建线程,就相当于雇了个人来干活,我们得告诉他要干啥活,他才能去执行。

如何告诉他要干啥活呢?

我们有如下方法,java中创建线程的写法有很多种,如下所示:

  1. 继承Thread,重写run方法
  2. 实现Runnable接口
  3. 使用匿名内部类,继承Thread
  4. 使用匿名内部类,实现Runnable接口
  5. 使用Lambda表达式

下面分别进行介绍:

1、继承Thread,重写run方法

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("hello thread");
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

t.start();

start方法是线程中的一个特殊方法作用是创建一个线程。

在上面代码中start这个方法创建了一个新的线程,新的线程负责执行run方法并不是start方法里面调用了run方法,是新的线程调用的run方法当run方法执行完时,新的线程自然销毁。

那么start是如何创建一个新线程的?

调用操作系统提供的API(系统调用),通过操作系统内核创建新线程的PCB,并且把要执行的指令交给这个PCB,当PCB被调度到CPU上执行的时候,也就执行到了线程run方法中的代码了。

在main方法中直接打印hello world,和在main方法中调用start方法的上述做法有啥区别?

如果只是在main方法中直接打印hello world,这个java进程就只有一个线程(调用main方法的线程),也就是主线程。

在main方法中调用t.start(),是主线程调用start方法创建出一个新的线程,新的线程调用run方法执行其中的代码。这个java进程中有两个线程。

如果把 t.start(); 改成 t.run(); 有什么区别吗?

有很大区别。

t.run(); 的话,这个java进程中还是只有一个主线程。所有的活都是主线程一个人干的。因为new Thread对象的操作并不创建线程,只有调用了start方法才是真正创建了PCB,才真正有个货真价实的线程。

2、实现Runnable接口

解耦合,目的是让线程线程要干的活之间分离开

未来如果要改代码,不用多线程了,使用多进程,或者线程池,协程......此时代码改动比较小。

//Runnable 作用:描述一个”要执行的任务“, run方法就是执行任务的细节
class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("hello world");
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        //这只是描述了个任务,就是线程要干的活
        Runnable runnable = new MyRunnable();
        //把任务交给线程来执行
        Thread t = new Thread(runnable);
        t.start();
    }
}

3、使用匿名内部类,继承Thread

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        t.start();
    }
}

 

红框框里是一个匿名内部类对象,这里做了两件事:

1、创建了一个Thread的子类,继承Thread类,(子类没有名字,所以才叫“匿名”)。

2、对子类进行实例化(new),让 t 引用指向该实例。

4、使用匿名内部类,实现Runnable接口

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread t = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println("hello world");
                    }
                }
        );
        t.start();
    }
}

5、使用Lambda表达式

直接把 lambda 传给 Thread 的构造方法

lambda 就是个匿名方法

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(
                () -> {
                    System.out.println("hello world");
                }
        );
        t.start();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis常见缓存问题

目录 缓存穿透 造成缓存穿透的原因 缓存穿透问题解决方案 1、缓存空对象返回 2、布隆过滤器 缓存失效(击穿) 缓存雪崩 热点缓存key重建优化 缓存与数据库双写不一致 1、双写不一致情况 2、读写并发不一致 解决方案 缓存穿透 缓存穿透是指查询一个根本不存在的数据&…

通过代理如何调通openai的api

调通openai的api 一、前提二、通过curl调通openai的api三、通过python调通openai的api 一、前提 会魔法上网本地运行代理软件,知道端口号(如1081)。 127.0.0.1:1081二、通过curl调通openai的api 如果在国外,没有qiang&#xff…

AI大模型开发架构设计(3)——如何打造自己的大模型

文章目录 如何打造自己的大模型1 新时代职场人应用AIGC的5重境界2 人人需要掌握的大模型原理职场人都能听懂的大语音模型的训练过程职场人都能听得懂的大语言模型的Transformer推理过程 3 如何构建自己的大模型需要具备三个方面的能力LangChain是什么?LangChain主要…

【音视频】基于ffmpeg对视频的切割/合成/推流

背景 基于FFmpeg对视频进行切割、合成和推流的价值和意义在于它提供了一种高效、灵活且免费的方式来实现视频内容的定制、管理和分发。通过FFmpeg,用户可以轻松地剪辑视频片段,根据需要去除不必要的部分或提取特定时间段的内容,从而优化观看…

【数据库原理】(37)Web与数据库

随着网络的高速发展和网络服务的日趋完善,网络上的信息量呈几何级数增长。为了有效地组织、存储、管理和使用网上的信息,数据库技术被广泛地应用于网络领域。特别是在Internet上,已建立了数以万计的网站,其中大中型网站的后台大多…

链表中倒数第k个结点(附带源码)

目录 代码部分: 核心:看图 代码部分: struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {// write code here// write code hereif (k 0){return NULL;}else{struct ListNode* slow pListHead, * fast pListHead;//…

一个非常流行的R语言调色板:RColorBrewer

R 语言有许多非常优秀的调色板,本文就介绍一个非常流行的,我也经常在用的调色板 R 包:RColorBrewer。 安装 install.packages("RColorBrewer") 加载 library(RColorBrewer) library(knitr) 初探 ?RColorBrewer 在帮助页面可以看到…

雨云VPS使用我的世界整合包开服教程,Pokehaan Craft 2整合包服务器搭建教程

Minecraft整合包服务器搭建教程,宝可梦/神奇宝贝整合包(Pokehaan Craft 2)开服教程。 其他整合包也可以参考此教程。要看这个整合包的游戏截图可以翻到文章最底下。 5分钟免费开一个MC服!雨云免费服务器领取教程&我的世界开…

开源项目盘点-学习类

1,freeCodeCamp 地址:https://github.com/freeCodeCamp/freeCodeCamp 描述:一个程序员学习网站,里面有全栈开发、机器学习的相关知识,是完全免费的,该网站有上千道编码挑战题来帮助你来练习你的技能。 提…

springboot集成easypoi

easypoi,主打的功能就是容易,通过简单的配置&#xff0c;就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出 pom导入依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star…

9.4 Lambda表达式

9.4 Lambda表达式 1 Lambda语法2. 基于Lambda实现函数式编程3. Stream流式处理 1 Lambda语法 2. 基于Lambda实现函数式编程 3. Stream流式处理

各分地域如果流量大的情况下 使用什么组网方式最好?V批N还是SDWAN或者其他?

环境&#xff1a; V批N SDWAN MPLS 问题描述&#xff1a; 各分地域如果流量大的情况下 使用什么组网方式最好&#xff1f;V批N还是sdwan或者其他&#xff1f; 解决方案&#xff1a; 当各地域之间的流量较大时&#xff0c;选择合适的组网方式可以提供更好的网络性能和可靠…

快速玩转 Mixtral 8x7B MOE大模型!阿里云机器学习 PAI 推出最佳实践

作者&#xff1a;熊兮、贺弘、临在 Mixtral 8x7B大模型是Mixtral AI推出的基于decoder-only架构的稀疏专家混合网络&#xff08;Mixture-Of-Experts&#xff0c;MOE&#xff09;开源大语言模型。这一模型具有46.7B的总参数量&#xff0c;对于每个token&#xff0c;路由器网络选…

【数据结构初阶】——顺序表

本文由睡觉待开机原创&#xff0c;转载请注明出处。 本内容在csdn网站首发 欢迎各位点赞—评论—收藏 如果存在不足之处请评论留言&#xff0c;共同进步&#xff01; 这里写目录标题 1.数据结构2.顺序表线性表顺序表的结构 3.动态顺序表的实现 1.数据结构 数据结构的概念&…

2024年【中级消防设施操作员(考前冲刺)】考试题库及中级消防设施操作员(考前冲刺)免费试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 中级消防设施操作员&#xff08;考前冲刺&#xff09;考试题库参考答案及中级消防设施操作员&#xff08;考前冲刺&#xff09;考试试题解析是安全生产模拟考试一点通题库老师及中级消防设施操作员&#xff08;考前冲…

外呼机器人有什么优势?

外呼机器人有什么优势&#xff1f;值得受到大多数电销企业的追捧&#xff01; 1、电话外呼效率高&#xff1a; 每天可拨打的电话数量是人工的5-10倍&#xff0c;人工一天只能拨打200-300通电话&#xff0c;机器人每天能打3000通电话以上&#xff0c;无须休息&#xff0c;按照…

洛谷P1161 开灯

这倒也是水题&#xff0c;我们可以建立一个数组&#xff0c;数组的下标就是编号&#xff0c;我们要注意的是浮点数乘法的结果要转化成整数&#xff0c;才能当做下标&#xff0c;因为题目给的是整数编号。 # include <stdio.h> int main() {int a[1000000] { 0 }, n, t,…

使用定时器外设的输入捕捉功能及测量脉冲宽度

使用定时器外设的输入捕捉功能及测量脉冲宽度 文章目录 使用定时器外设的输入捕捉功能及测量脉冲宽度Introduction硬件定时器外设输入捕获功能的机制使用两个通道&#xff08;引脚&#xff09;的单边沿触发输入捕获使用单通道&#xff08;引脚&#xff09;的双边沿触发输入捕获…

16.5 参考文献——深度学习定位

16.5 一种高效鲁棒的多楼层室内环境指纹定位方法 同济大学 Zhao Y, Gong W, Li L, et al. An Efficient and Robust Fingerprint Based Localization Method for Multi Floor Indoor Environment[J]. IEEEa Internet of Things Journal, 2023. 2.相关工作 B.基于深度学习的…

SAI实例研究

实例1 creature.id 15937&#xff08;smart_script.entryorguid&#xff09;的SAI设置&#xff1a; 第1条(id 0&#xff09; 当 creature 进入战斗后&#xff08;event_type 0&#xff09;&#xff0c;creature 对当前目标&#xff08;target_type 2&#xff09;周期性施…