什么是进程、线程,什么是并发、并行及线程的创建和线程的基本使用

news2024/9/20 20:29:42

一、什么是程序、进程、线程

1、什么是程序
程序可以理解为是我们执行的一段代码,是一种静态的概念

2、什么是进程
进程是指运行中的程序,是一个动态的概念。进程有它自身的产生、存在和消亡的过程(进程产生就会占用内存空间,反之如果进程消亡则会释放内存空间)
比如:我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间;又或是,当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。

3、什么是线程
线程由进程创建的,是进程的一个实体
一个进程可以拥有多个线程
比如:你可以使用迅雷同时下载三个文件,这时就可以理解有三个线程在同时干活

二、单线程、多线程

1、什么是单线程
单线程:同一时刻,只允许执行一个线程。

2、什么是多线程
多线程:同一时刻,可以执行多个线程。
比如:一个qq进程,可以同时打开多个聊天窗口;又或是,一个迅雷进程,可以同时下载多个文件

三、并发、并行

1、什么是并发
并发:同一时刻,多个任务交替执行,造成一种“貌似同时”的错觉。简单的说,单个CPU实现的多任务就是并发。
比如:人在开车时候打电话,其实是你的大脑在同一时刻,对开车和打电话这两个任务交替执行的;又或是,假设你的电脑是单核CPU,但同时需要执行QQ、迅雷两个软件(进程),实际上,在同一时刻只能执行一个进程,如果要执行多个进程的话,就需要不停的切换,多个进程交替执行,看上去就像两个或多个进程同时在工作。

2、什么是并行
并行:同一时刻,多个任务同时执行。多核CPU可以实现并行。
比如:我的电脑有两个CPU,那么在同一时刻,一个CPU可以执行QQ这个进程,另一个CPU可以执行迅雷这个进程,同一时刻,多个任务可同时执行

3、并发和并行可能同时存在
比如说,你的电脑是两核CPU,而你想同时执行QQ、迅雷、微信这三个进程,那么假设其中一个CPU同一时刻交替执行QQ和微信,而另外一个CPU则执行迅雷,那么对于CPU1来说某一时刻交替执行QQ和微信这就是并发,而对CPU1和CPU2来说,其实是在并行执行任务,此时就可以理解并发和并行同时存在。

四、线程的基本使用

(一)创建线程的两种方式:

1、继承Thread类,重写run方法。
2、实现Runnable接口,重写run方法。
在这里插入图片描述

(二)线程基本使用

方式一:通过继承Thread类,重写run方法

编写程序,开启一个线程,该线程每间隔1s在控制台输出“Hello,我是小猫咪”,且当输出10次后结束该线程。

1.public class project1 {  
2.    public static void main(String[] args) throws Exception{  
3.  
4.        //创建一个Cat对象,可以当作线程使用  
5.        Cat cat = new Cat();  
6.        cat.start();               //启动线程  
7.    }  
8.}  
9.  
10./** 
11. * 创建线程方法1:继承Thread类,重写run方法 
12. * 说明: 
13. * 1、当一个类继承了Thread类,该类就可以当作线程使用 
14. * 2、我们通过重写run方法,来实现自己的业务逻辑代码 
15. */  
16.class Cat extends Thread{  
17.    int times = 0;       //用于记录输出的次数
18.    @Override  
19.    public void run() {//重写run方法,写上自己的业务代码  
20.        while(true){  
21.            //业务需求:该线程每间隔1秒,在控制台输出“Hello,我是小猫咪”  
22.            System.out.println("Hello,我是小猫咪" + (++times));  
23.  
24.            try {  
25.                //让该线程休眠1s  
26.                Thread.sleep(1000); //该方法的单位是ms(毫秒)  
27.            } catch (InterruptedException e) {  
28.                throw new RuntimeException(e);  
29.            }  
30.            if (times == 10){  
31.                break;          //当times 为10时,退出while循环,这时线程也就退出。。  
32.            }  
33.        }  
34.    }  
} 

运行结果,如下:
在这里插入图片描述

方式二:通过实现Runnable接口的方式,重写run方法

1、什么情况下会用到通过实现Runnable接口的方式来创建线程呢?
说明:
因为Java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然是不可能的了。因此引入了另外一种创建线程的方式,就是通过实现Runnable接口的方式来创建线程。

2、编写一个程序,该程序可以每间隔1s,在控制台输出”小狗汪汪叫。。。”,输出10次后,自动退出,请使用实现Runnable接口的方式,创建线程实现。
具体代码如下:

public class project02 {  
    public static void main(String[] args) {  
        Dog dog = new Dog();  
        //dog.start();        //注意:因为通过实现Runnable接口的方式创建的Dog不能直接调用start方法  
        Thread thread = new Thread(dog);  
        thread.start();  
    }  
}  
  
class Dog implements Runnable{ //通过实现Runnable接口的方式,开发线程  
    int count = 0;  
    @Override  
    public void run() {  
        while (true){  
            System.out.println("小狗汪汪叫。。 " + ++count + "  线程的名称为:" + Thread.currentThread().getName());  
  
            //休眠1s  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                throw new RuntimeException(e);  
            }  
  
            if (count == 10){  
                break;  
            }  
        }  
    }  
} 

3、运行结果如下:

在这里插入图片描述

(三)线程的启动流程

以上述(二)中猫咪程序为例进行讲解。
在这里插入图片描述

1、首先,你运行了这个程序,即执行了Run操作,就相对于你启动了这个进程
2、启动这个进程后,马上就会进入我们的主方法(main方法),也就是启动了主线程(main线程)
3、启动主线程后,又在主线程中启动了另外一个线程,Thread-0线程(即通过stat()方法启动了Cat线程)
4、需要理解:主线程结束后,进程并不一定就结束了,因为主线程的子线程可能还没有结束,反正,主线程结束并且主线程的子线程也结束后,进程才会结束。
注意
1、当main启动一个子线程 Thread-0,主线程不会阻塞(即不需要等你子线程的start()方法执行完成后才往下走),会继续执行。
2、换句话说:主线程在启动子线程后,主线程中子线程下面的代码也会继续执行
3、即此时主线程和子线程中的代码同时在交替执行
举例代码如下:

public class project1 {  
    public static void main(String[] args) throws Exception{  
  
        //创建一个Cat对象,可以当作线程使用  
        Cat cat = new Cat();  
        cat.start();               //启动线程  
  
        //说明:当main启动一个子线程 Thread-0,主线程不会阻塞,会继续执行  
        //换句话说:主线程在启动子线程后,主线程中子线程下面的代码也会继续执行  
        //即此时主线程和子线程中的代码同时在交替执行  
        System.out.println("主线程继续执行:" + "主线程名称为:" + Thread.currentThread().getName());  
        for (int i = 0; i < 10; i++){  
            System.out.println("主线程 i= " + i);  
            //让主线程休眠1s  
            Thread.sleep(1000);  
        }  
    }  
}

运行结果如下:
在这里插入图片描述

(四)线程启动为什么使用的是start()方法

不知道小伙伴们在学习线程时候是否会有这样的疑问,线程的启动为什么使用的是start()方法,我们在创建线程时候,无论是使用继承Thread类的方式,还是实现Runnable接口的方式,都是重写的run方法,但是为什么在启动线程的时候是调用的start()方法,而不是run()方法呢?
不妨我们来做个验证,将上述代码案例改为通过调用run方法来创建线程,看看结果如何。
1、将上述代码进行修改,修改如下:

public class project1 {  
    public static void main(String[] args) throws Exception{  
  
        //创建一个Cat对象,可以当作线程使用  
        Cat cat = new Cat();  
     //   cat.start();               //启动线程  
        cat.run();                   //假设,我们现在通过调用run()方法,来启动线程(修改的地方)  
  
        //说明:当main启动一个子线程 Thread-0,主线程不会阻塞,会继续执行  
        //换句话说:主线程在启动子线程后,主线程中子线程下面的代码也会继续执行  
        //即此时主线程和子线程中的代码同时在交替执行  
        System.out.println("主线程继续执行:" + "主线程名称为:" + Thread.currentThread().getName());  
        for (int i = 0; i < 10; i++){  
            System.out.println("主线程 i= " + i);  
            //让主线程休眠1s  
            Thread.sleep(1000);  
        }  
    }  
}  

2、我们来看看输出结果:
在这里插入图片描述

此时此刻,根据输出结果我们会发现,这段代码先是输出了主函数中调用的cat.run()对应的执行结果,等到cat.run()这个函数执行完成后,才会继续执行主函数中cat.run()方法下面的语句。

结论:
为什么启动线程要使用start()方法,而不是通过调用重写的run()方法呢?
因为使用cat.run()方法,其实并非是真正的启动线程,而仅仅是调用了重写的run()方法,只有等待run()方法执行完成后才能执行其主函数的其他语句,而实质并非是达到了启动线程的效果,故启动线程需要使用start()方法。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【WSL】[04]从C盘解放出来WSL的linux镜像

前言&#xff1a; C盘的硬盘资源有限&#xff0c;虚拟机的需求无限&#xff0c;所以&#xff0c;要把无限的硬盘需求搞到其他盘去才行啊 方案1&#xff1a;利用工具&#xff1a;move-wsl 1 管理员运行PowerShell,创建WSL的工作目录 移动前&#xff0c;C盘的空间大小&#xf…

vue-element-表格 Excel 【导出】功能

表格Excel导出功能 1. 将点击导出按钮添加点击事件click“handleDownload” 并在method中创建方法 <el-button type"danger" size"small" click"handleDownload">excel导出</el-button>复制下面的方法 or 去vue-element-admin中的s…

分享62个PHP源码,总有一款适合您

链接&#xff1a;https://pan.baidu.com/s/17mzEPqFhZp0UEvznSviiEA?pwdnjin 提取码&#xff1a;njin PHP源码 分享62个PHP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后…

【C语言简明教程】探究整型数据在内存中的存储

概述 我们知道一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。那么整型数据在所开辟内存中到底是如何存储的&#xff1f; 目录 概述 原码、反码、补码 什么是原码、反码和补码&#xff1f; 为什么使用补码存储&#xff1f; 大小端存储 - 数据…

Hadoop高手之路6-ZooKeeper

文章目录Hadoop高手之路6-Zookeeper分布式协调服务一、Zookeeper简介二、Zookeeper的特性1. 一致性C2. 可靠性3. 顺序性4. 原子性A5. 实时性三、Zookeeper分布式集群的部署1. 下载安装包2. 上传3. 解压4. 配置环境变量5. 配置Zookeeper1) 复制一个配置模板文件2) 修改配置文件3…

C语言排序算法

冒泡排序&#xff08;英语&#xff1a;Bubble Sort&#xff09;是一种简单的排序算法。它重复地走访过要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序&#xff08;如从大到小、首字母从A到Z&#xff09;错误就把他们交换过来。 过程演示&#xff1a; #i…

shell第二天练习

题目 1、编写一个 Shell脚本&#xff0c;程序执行时从键盘读入一个目录名&#xff0c;如果用户输入的目录不存在&#xff0c;则提示file does not exist&#xff1b;如果用户输入的不是目录则提示用户必须输入目录名&#xff1b;如果用户输入的是目录则显示这个目录下所有文件…

django笔记《模型和数据库一》

文章目录1 前言2 创建一个demo项目2.1 修改配置文件3 模型3.1 主键3.2 django 内置字段类型3.3 自定义字段类型3.4 django字段选项3.5 字段备注名3.5 META3.6 关联关系3.6.1 多对一关系3.6.2 多对多关系3.6.3 一对一关系3.7 字段命名限制3.8 模型属性&#xff1a;Model.objects…

基于springboot+Vue前后端分离的招聘管理系统(程序+数据库+文档)

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

A Survey on Deep Learning Techniques for Stereo-based Depth Estimation论文阅读

1. 摘要 估计RGB图片的深度是一个长期存在的病态问题&#xff0c;计算机视觉、图形学、机器学习社区已经探索了数十年。立体匹配是最广泛见诸文献的技术之一&#xff0c;因为它与人类的双目系统有强关联。传统上&#xff0c;利用多张图片的人工特征匹配来处理基于立体的深度估…

nginx 实现图片防盗链功能

在搜索浏览网页的时候&#xff0c;发现一篇文章是从我的个人网站转载的&#xff0c;但是没有注明出处&#xff0c;文章中的图片也没有本地化处理&#xff0c;还是从我的服务器请求&#xff0c;这就无形中增加了我的服务器的开销&#xff0c;于是有了设置防盗链功能这一想法。 …

Kafka 核心源码解读【五】--延迟操作模块

文章目录1 TimingWheel&#xff1a;探究Kafka定时器背后的高效时间轮算法1.1 时间轮简介1.2 源码层级关系1.3 时间轮各个类源码定义1.3.1 TimerTask 类1.3.2 TimerTaskEntry 类1.3.3 TimerTaskList 类1.3.4 TimingWheel 类1.4 总结2 DelayedOperation&#xff1a;Broker是怎么延…

【Vue】九、vue-element-admin

后端程序员的vue学习之路一、介绍二、功能特性三、前置准备四、前置知识五、项目结构说明&#xff1a;六、安装运行一、介绍 vue-element-admin 是一个后台前端解决方案&#xff0c;它基于 vue 和 element-ui实现&#xff0c;它使用了最新的前端技术栈&#xff0c;内置了动态路…

深入理解计算机系统_程序的链接过程

编辑好的程序&#xff0c;依次经过预处理(注释&#xff0c;宏替换&#xff0c;头文件包含&#xff0c;生成.s文件)、编译(生成汇编文件.s )、汇编(生成静态可重定位目标文件&#xff0c;文件名是.o)、链接后最终得到可执行目标文件&#xff0c;这个笔记记录一下&#xff0c;链接…

信号处理系列之死区滤波器(DeadZone)

信号处理专栏相关限幅滤波的文章,可以参看下面的链接,这里不再赘述: 博途PLC信号处理系列之限幅消抖滤波_RXXW_Dor的博客-CSDN博客关于限幅滤波可以参看下面这篇文章PLC信号处理之限幅滤波(西门子三菱FB)_RXXW_Dor的博客-CSDN博客限幅滤波是一种消除随机干扰的有效方法,比…

WordPress元宇宙和VR(虚拟现实)最佳插件汇总

近年来&#xff0c;虚拟现实&#xff08;VR &#xff09;和元宇宙&#xff08;Metaverse &#xff09;变得越来越流行。它使用户能够在舒适的家中享受身临其境的体验。此外&#xff0c;将此功能添加到您的网站可以帮助您的内容更具交互性&#xff0c;这可能会带来更多转化。幸运…

RHCE——ansible安装配置(2)

安装并且配置ansible&#xff1a; 1)安装和配置ansible以及ansible控制节点server.example.com如下&#xff1a; 2)创建一个名为/home/student/ansible/inventory的静态库存文件如下所示&#xff1a; 2.1)node1 是dev主机组的成员 2.2)node2是test主机组的成员 2.3)node1和node…

c++动态内存管理

1.回顾c语言中的动态内存管理 在c语言中&#xff0c;我们想要动态开辟一段空间&#xff0c;需要使用malloc&#xff0c;calloc&#xff0c;realloc几个函数 void* malloc (size_t size); //在堆上申请size个字节的空间void* calloc (size_t num, size_t size); //第一个参数是…

压缩空气储能研究(Matlab代码)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

CMMI之技术预研

技术预研&#xff08;Technical Pre-Research, TPR&#xff09;是指在立项之后到开发工作完成之前的时间内&#xff0c;对项目将采用的关键技术提前学习和研究&#xff0c;以便尽可能早地发现并解决开发过程中将会遇到的技术障碍。 技术预研过程域是SPP模型的重要组成部分。本…