【javaEE-有关CPU进程和线程实现的并发编程及二者的区别】

2024-06-13 12:20

本文主要是介绍【javaEE-有关CPU进程和线程实现的并发编程及二者的区别】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🔥🔥🔥有关进程并发编程开发的成本问题

这次之前其实我们所有的写的程序都是使用单核心来运行的,但是一般我们的计算机都有很多核心,如果我们编程的时候,只使用一个核心的话,其实这是一个非常大的浪费,所以我们引进了多进程这种并发编程来充分利用计算机的多核心。但是随着我们的需求越来越大,进程的一些缺点就显现出来了。

  • 创建和销毁进程的成本很大
  • 越来越多的需求场景需要一种更方便的并发编程形式
  • 线程的出现

由此我们发明了一个新的并发编程的形式,线程(Thread),对比进程,它的创建和销毁成本更小,更轻量。因此现在的主流并发编程的形式就是多线程编程。

在这里插入图片描述

🔥🔥🔥多线程编程

对于进程来说,一个进程是由一组PCB类似于结构体的形式对数据进行描述,进一步的通过链表的形式将数据组织起来。对于线程来说,一个线程是只有有一个PCB结构的形式,所以这里就有一个包含关系:一个进程中可以包含多个线程,此时每一个线程都可以独立的在CPU上调度执行,这里我们对进程和线程做一个总结:

  • 进程是系统资源分配的基本单位
  • 线程是cpu调度执行的基本单位

一个可执行的程序,双击exe文件,系统就会创建一个进程,给这个进程中分配一些系统资源(硬盘,cpu,内存,网络带宽等)。在这个进程中会创建一个或多个线程。这些线程才在cpu中调度执行。同一个进程中的多个线程其实是共用同一份系统资源的。

对比进程,线程是更轻量的,主要是在我们创建一个进程的时候,就已经创建了一个线程了,同时就会分配系统资源,后序我们在创建第二个第三个线程的时候,就不用再分配资源了~,因此他就省去了分配资源的过程。也省去了释放资源的过程。在这里插入图片描述

🔥🔥🔥系统分析多线程调度执行过程

比如说现在有请我们最可爱的joey老铁上场,此时在一个房间里他要一个人吃完100只鸡。
在这里插入图片描述
为了提高老铁的吃鸡效率,我们可以引用多进程的概念,在创建一个房间,还是一个joey老铁,只需要吃50只鸡。
在这里插入图片描述
这样确实提高了joey吃鸡的效率,但是我们其实不难发现这种效率是非常低的,我们显然可以用一个更简单的方式提高吃鸡的效率,我们可以在一个房间里引进多个joey老铁,这样的方式不仅大大提高了吃鸡的效率,而且大大缩减了成本的损耗。这其实就是多线程的概念。相比于多进程,这种形式效率是极高的。
在这里插入图片描述

那我们就自然的想到,在引进一些线程,会不会进一步提高效率呢?当然会!!!
在这里插入图片描述
但是当我们将线程增加带一些程度的时候,就会出现问题了~
在这里插入图片描述
此时就再也无法通过增加线程的方式,提高程序执行的效率了,因为桌子的空间是有限的,我们增加多个joey后,势必会有一些joey老铁是吃不到桌子上的鸡的,即线程多了,cpu的资源是有限的,这样就无法提高效率了。

有时甚至可能会由于线程的增多,导致线程可能会争夺系统资源,最后导致系统崩溃!!!

🔥🔥🔥线程和进程的概念即区别

1. 进程包含线程: 即一个进程中可以包含一个或者多个线程,但是不能没有线程,当我们创建一个main函数时就是一个主线程。
2. 进程是系统资源分配的基本单位,线程是系统调度执行的基本单位。
3. 同一个进程中的所有线程其实是共用同一份系统资源的(硬盘,内存,网络带宽等)
4. 线程是当下实现并发编程的主流方式,通过多线程可以很好的利用cpu的多核心特性~但是并不是线程越多越好的,随着线程的增多(当然创建线程也会有一定的开销),可能会导致多个线程之间争夺系统资源,甚至导致系统的崩溃
5. 多个线程之间,其实也存在一定的安全问题,当一个线程产生异常时,可能也会影响其他线程的正常执行~
6. 多个进程之间一般是不会相互影响的,、一个进程崩溃,并不会影响其他进程的运行(这也称为“进程的隔离性”)。在这里插入图片描述

这个问题非常重要,是面试的高频问题,一定要牢记于心啊!!!

🔥🔥🔥如何在java中创建线程

线程其实是属于操作系统中的概念,操作系统会提供api,供程序员调用,但是不同的操作系统其实对应的api是不同的,java中jvm已经替我们将这些api封装好了,我们只需要关注jvm中的这一套api就好了。
一般我们通过使用Thread这个类来完成多线程的开发。

🗼🗼🗼继承Thread重写Run方法创建线程

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

这里的run函数的主体其实就是我们完成线程主体任务的地方,在这里实现代码的主体部分,然后通过start方法,真正在内存中创建一个线程,通过回调函数run执行相关操作。回调函数就是用户手动定义了,但是没有手动调用,但是最后被系统调用的函数。

🗼🗼🗼实现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 Demo3 {public static void main(String[] args) throws InterruptedException {MyRunnable runnable=new MyRunnable();Thread t=new Thread(runnable);t.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}
}

这里的sleep是Thread中的库函数,可以不导入包直接调用,但是这里存在一个受查异常,所以要进行异常捕捉。由于父类中的run方法并没有这个异常所以我们只能利用try-catch,而不能把异常向上抛出。

🗼🗼🗼继承Thread利用匿名内部类实现一个线程

public static void main(String[] args) throws InterruptedException{Thread t=new Thread(){@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);}}

匿名内部类定义在一个类的内部,只能使用一次。

🗼🗼🗼实现Runnable利用匿名内部类创建线程

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);}}}});while (true) {System.out.println("hello main");Thread.sleep(1000);}}

🗼🗼🗼利用lamda表达式创建一个线程

    public static void main(String[] args) throws InterruptedException{Thread t=new Thread(()->{while(true){System.out.println("thread hello");try{Thread.sleep(1000);}catch (InterruptedException e){throw new RuntimeException(e);}}},"自定义线程");t.start();while(true){System.out.println("hello main");Thread.sleep(1000);}}

好了,今天就分享这么多了,感兴趣的话关注不迷路哦

这篇关于【javaEE-有关CPU进程和线程实现的并发编程及二者的区别】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1057288

相关文章

Qt实现对Word网页的读取功能

《Qt实现对Word网页的读取功能》文章介绍了几种在Qt中实现Word文档(.docx/.doc)读写功能的方法,包括基于QAxObject的COM接口调用、DOCX模板替换及跨平台解决方案,重点讨论... 目录1. 核心实现方式2. 基于QAxObject的COM接口调用(Windows专用)2.1 环境

MySQL查看表的历史SQL的几种实现方法

《MySQL查看表的历史SQL的几种实现方法》:本文主要介绍多种查看MySQL表历史SQL的方法,包括通用查询日志、慢查询日志、performance_schema、binlog、第三方工具等,并... 目录mysql 查看某张表的历史SQL1.查看MySQL通用查询日志(需提前开启)2.查看慢查询日志3.

Java实现字符串大小写转换的常用方法

《Java实现字符串大小写转换的常用方法》在Java中,字符串大小写转换是文本处理的核心操作之一,Java提供了多种灵活的方式来实现大小写转换,适用于不同场景和需求,本文将全面解析大小写转换的各种方法... 目录前言核心转换方法1.String类的基础方法2. 考虑区域设置的转换3. 字符级别的转换高级转换

使用Python实现局域网远程监控电脑屏幕的方法

《使用Python实现局域网远程监控电脑屏幕的方法》文章介绍了两种使用Python在局域网内实现远程监控电脑屏幕的方法,方法一使用mss和socket,方法二使用PyAutoGUI和Flask,每种方... 目录方法一:使用mss和socket实现屏幕共享服务端(被监控端)客户端(监控端)方法二:使用PyA

MyBatis-Plus逻辑删除实现过程

《MyBatis-Plus逻辑删除实现过程》本文介绍了MyBatis-Plus如何实现逻辑删除功能,包括自动填充字段、配置与实现步骤、常见应用场景,并展示了如何使用remove方法进行逻辑删除,逻辑删... 目录1. 逻辑删除的必要性编程1.1 逻辑删除的定义1.2 逻辑删php除的优点1.3 适用场景2.

SpringBoot简单整合ElasticSearch实践

《SpringBoot简单整合ElasticSearch实践》Elasticsearch支持结构化和非结构化数据检索,通过索引创建和倒排索引文档,提高搜索效率,它基于Lucene封装,分为索引库、类型... 目录一:ElasticSearch支持对结构化和非结构化的数据进行检索二:ES的核心概念Index:

C#借助Spire.XLS for .NET实现在Excel中添加文档属性

《C#借助Spire.XLSfor.NET实现在Excel中添加文档属性》在日常的数据处理和项目管理中,Excel文档扮演着举足轻重的角色,本文将深入探讨如何在C#中借助强大的第三方库Spire.... 目录为什么需要程序化添加Excel文档属性使用Spire.XLS for .NET库实现文档属性管理Sp

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

Java方法重载与重写之同名方法的双面魔法(最新整理)

《Java方法重载与重写之同名方法的双面魔法(最新整理)》文章介绍了Java中的方法重载Overloading和方法重写Overriding的区别联系,方法重载是指在同一个类中,允许存在多个方法名相同... 目录Java方法重载与重写:同名方法的双面魔法方法重载(Overloading):同门师兄弟的不同绝

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav