进程与线程

2023-09-22 09:10:22

1进程

1.1进程的概念

进程就是正在运行的程序,它代表了程序所占用的内存区域

1.2进程的特点

  • 独立性

进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间

  • 动态性

进程与程序的区别在于.程序只是一个静态的指令集合,而进程是一个正在系统中动态的指令集合;程序加入了时间的概念以后,称为进程,具有自己的生命周期和各种不同的状态,这些概念都是程序所不具备的.

  • 并发性

多个进程可以在单个处理器CPU上并发执行,多个进程之间不会互相影响

1.3并行与并发

2线程

2.1线程的概念

线程是操作系统OS能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位一个进程可以开启多个线程,其中有一个主线程来调用本进程中的其他线程我们看到的进程的切换,切换的也是不同进程的主线程多线程扩展了多进程的概念,使的同一个进程可以同时并发处理多个任务


2.2 进程与线程的关系


一个操作系统中可以有多个进程,一个进程中可以包含一个线程(单线程程序),也可以包含多个线程(多线程程序)

3多线程的特性


3.1 随机性


线程的随机性指的是同一时刻,只有一个程序在执行我们宏观上觉得这些程序像是同时运行.但是实际上微观时间是因为CPU在高效的切换着,这使得各个程序从表面上看是同时进行的,也就是说.宏观层面上,所有的进程/线程看似同时运行,但是微观层面上同一时刻,一个CPU只能处理一件事.切换的速度甚至是纳秒级别的,非常快,并且线程执行效果具有随机性,各个线程的执行顺序是不可控的,具体怎么执行,取决于CPU的调度,时间片的分配,用户是控制不了的

3.2 CPU分时调度


时间片,即CPU分配给各个线程的一个时间段,称作它的时间片,即该线程被允许运行的时间,如果在时间片用完时线程还在执行,那CPU将被剥夺并分配给另一个线程,将当前线程挂起,如果线程在时间片用完之前阻塞或结束,则CPU当即进行切换,从而避免CPU资源浪费,当再次切换到之前挂起的线程,恢复现场,继续执行。

3.3 线程的状态


由于线程状态比较复杂,由易到难,先学习线程的三种基础状态及其转换,简称”三态模型”:

  • 就绪(可运行)状态:线程已经准备好运行,只要获得CPU,就可立即执行
  • 执行(运行)状态: 线程已经获得CPU,其程序正在运行的状态,注意只有就绪才能转执行
  • 阻塞状态:正在运行的线程由于某些事件 (/O请求等)暂时无法执行的状态

线程生命周期    主要有五种状态:

1.新建状态(New):当线程对象创建后就进入了新建状态,如:Threadt= new MyThread():

2.就绪状态(Runnabie):当调用线程对象的start()方法线程即为进入就绪状态;

处于就绪(可运行)状态的线,只是说明线程已经做好准备,随时等待CPU调度执行,并不是执行了t.start()此线程立即就会执行

3.运行状态(Running)   当CPU调度了处于就状态的线程时,此线程才是真正的执行,即进入到运行状态,

就绪状态是进入运行状态的唯一入口,也就是线程想要进入运行状态状态执行,先得处于就绪状态

4.阻塞状态(Blocked)处于运状态中的线程由于某种原因暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入就绪状态才有机会被CPU选中再次执行

根据阻塞状态产生的原因不同,阻塞状态又可可以细分成三种:

4.1等待阻塞:运行状态中的线程执行wait()方法,本线程进入到等待阻塞状态

4.2同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用)它就会进入同步阻塞状态 

4.3其他阻塞:调用线程的sleep()或者join(),以及发出了IO请求时,线程会进入到阻塞状态,当sleep()状态超时,join()等待线程终止或者超时,或者IO处理完毕时线程重新转入就绪状态

5.死亡状态(Dead)线程执行完了或者因异常退出了rn0万法该步程结束生命周期

4 多线程的几种创建方式之:继承Thread类


4.1概述


Thread类本质上是实现了Runnable接口的一个实例,代表一个线程的实例启动线程的唯一方法就是通过Thread类的start()实例方法,start()方法是一native方法它将通知底层提作系统最终由操作系统启动一个新线程,提作系统将执行run0
这种方式实现的多线程很简单,通过自己的类直接extends Thread,并重写run()方法,就可以自动启动新线程并执行自己定义的run(方法
模拟开启多个线程,每个线程调用run0方法


4.2构造方法(这里使用无参构造)

6.在测试类的main方法中创建线程对象,并运行run,但是
        MyThread t1 = new MyThread();
        //8.1   t1.run();
7.为了模拟多线程效果,所以至少需要创建两个线程,若只启动一个线程,就是单线程程序
        MyThread t2 = new MyThread();   
        //8.2   t2.run();
8.但是如果只是通过两个线程对象去调用run这个方法,程序就不知道要以多线程的方式启动,会按代码运行顺序的先后逻辑,先执行一个线程的任务,完成后再去执行另一个线程的任务,所以并没有抢占资源得到,所以  想要模拟多线程,需要启动start方法,注释掉run方法
        t1.start();
        t2.start();
9.start()是将线程添加到就绪队列,为就绪状态, 执行时机取决于操作系统何时选中,对应的是 <就绪状态>
10.当调用start()方法时,底层虚拟机会自动调用run方法执行线程的执行里面的业务
11.总结,线程执行效果具有随机性,各个线程的执行顺序是不可控的,具体怎么执行,取决于CPU的调度,和时间片的分配,我们控制不了
12运行结果是两个线程名交替出现,即表示不同的线程抢占到了CPU

代码实现:

package yichang2023.CGB.线程;

public class TestThread1 {

    public static void main(String[] args) {
//        6.在main方法中创建线程对象,并运行
        MyThread t1 = new MyThread();
        t1.run();
//        7.为了模拟多线程效果,所以至少需要创建两个线程,若只启动一个线程,就是单线程程序
        MyThread t2 = new MyThread();
        //9.1   t2.run();
 /*     8.如果只是通过两个线程对象调用run方法,程序不知道要以多线程的方式启动,
        会按代码运行顺序的先后逻辑,先执行一个线程的任务,完成后再去执行另一个线程的任务,所以并没有抢占资源得到*/

//      9.模拟多线程,需要启动start方法,注释掉run方法
        t1.start();
        t2.start();
//      10.start()是将线程添加到就绪队列,为就绪状态, 执行时机取决于操作系统何时选中,对应的是 <就绪状态>
//      11.当调用start()方法时,底层虚拟机会自动调用run方法执行线程的执行里面的业务
//      12.总结,线程执行效果具有随机性,各个线程的执行顺序是不可控的,具体怎么执行,取决于CPU的调度,时间片的分配,我们控制不了


//      13结果是两个线程名交替出现,即表示不同的线程抢到了CPU
    }
}


/*1.自定义线程类  方法一: 继承Thread  */
class MyThread extends Thread {

//2.必须要写一个run方法

    @Override
    public void run() {
        //3.自定义线程类的业务要写在重写的run方法中
        //4.因为super.run()表示默认调用父类的业务,用不着,所以注释掉
//        super.run();

        //5.下面来写自己的业务,例如获取当前线程名称 由于本类继承了Thread类,所以可以直接使用这个方法
        for (int i = 0; i < 10; i++) {
            System.out.println("当前线程名--->" + getName());
        }
    }

}

总结:

1.自定义一个类并 extends Thread 

2.重写run()在里面写业务

3.创建线程对象

4.调用start()
注意: 可以通过调用父类Thread的含参构造Thread(String name)给自定义线程对象起名字,调用方式: super(name); 

5 多线程的几种创建方式之:实现Runnable接口

注意:上面这种方法是让自定义的这个类以面向对象的思想来继承Thread ,就产生了局限性不能继承其他类了,会不利于程序后续开发,为了把这次继承机会留下来在以后更有需要的时候再使用,所以使用第二种面向接口的方法,更加灵活

    //1.自定义多线程类实现runnable接口
    class MyRunnable implements Runnable{
        //    2.实现接口中未实现的抽象方法  在里面写自定义业务
        @Override
        public void run() {
//        3.业务:打印10次线程名称
            for (int i = 0; i <10 ; i++) {
 
//        System.out.println(i+"----->"+getName());
                System.out.println(i+"---->"+Thread.currentThread().getName());
            }
//4.这里如果和之前一样,直接调线程的getName()方法就报错了,因为getName()是刚刚上一个自定义类继承的Thread类里面的方法,        而现在是实现runnable接口,就不能使用;在点进runnable接口底层发现里面就只有一个等着我去实现的抽象方法run ,所以还是要去Thread类里面找别的方法用,而如果想不创建对象就调其中的方法,只有一个办法,即<<静态>>
      }
 }

知识点:静态方法currentThread()    获取当前正在执行的线程对象;而由于Thread类是java.lang包下的, 所以可以不导包,静态方法直接用类名调用

System.out.println(Thread.currentThread().getName());

测试类中:

 class TestThread2 {
    public static void main(String[] args) {
5.创建线程对象--包含的是之前写的业务,即目标业务对象,只需要创建一次,相当于系统给所有玩家发布了同一个任务target
        MyRunnable target=new MyRunnable();
6.因为想要模拟多线程,就需要启动start方法,不能使用run方法,而当前的myRunnable测试类和MyRunnable接口都没有start()方法,所以需要通过下面这个含参的构造函数,将MyRunnable接口实现类myRunnable的对象与线程类Thread建立关系,从而使用Thread的start()方法以多线程的方式启动线程
        Thread t1=new Thread(target);
        Thread t2=new Thread(target);
        Thread t3=new Thread(target);
        Thread t4=new Thread(target);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

API 

实现代码:

package yichang2023.CGB.线程;
/*本类用于 多线程 实现方法二: 实现runnable接口*/


class TestThread2 {
    public static void main(String[] args) {
//        5.创建线程对象--包含的是之前写的业务,即目标业务对象,只需要创建一次,相当于系统给所有玩家发布了同一个任务target
        MyRunnable target = new MyRunnable();
//        6.因为想要模拟多线程,需要启动start方法,不能使用run方法,
//        而当前的myRunnable类和MyRunnable接口都没有start()方法
//        所以需要将MyRunnable接口实现类myRunnable的对象与线程类Thread建立关系
//        从而使用Thread的start()方法以多线程的方式启动线程
        Thread t1 = new Thread(target);
        Thread t2 = new Thread(target);
        Thread t3 = new Thread(target);
        Thread t4 = new Thread(target);
        t1.start();
        t2.start();
        t3.start();
        t4.start();

    }
}


//1.自定义多线程类 并实现runnable接口
class MyRunnable implements Runnable {
    //    2.实现接口中未实现的抽象方法  在里面写自定义业务
    @Override
    public void run() {
//        3.业务:打印10次线程名称
        for (int i = 0; i < 10; i++) {
/*      4.这里如果和之前一样,直接调线程的getName()方法就报错了,因为getName()是刚刚继承的Thread类里面的方法,
        而现在是实现runnable接口,但点进runnable接口底层发现里面就只有一个等着我去实现的抽象方法run
        所以还是要去Thread类里面找别的方法用,而如果想不创建对象就调其中方法,只有一个办法,即<<静态>>
        知识点:静态方法currentThread():获取当前正在执行的线程对象,而由于Thread类是java.lang包下的,
        所以可以不导包,静态方法直接用类名调用        */
//        System.out.println(i+"----->"+getName());
            System.out.println(i + "---->" + Thread.currentThread().getName());
        }

    }
}







总结:

1.自定义一个类implements Runnable

2.实现接口中未实现的run方法

3.打印当前线程名:Thread.carrentThread.getName()

4.创建目标业务对象,即实现进口的对象,包含了写的业务逻辑

5.创建线程对象  Thread t1=new Thread(target);

目的:为了把实现类与Thread建立关系,原因是想使用Thread的start方法,而非要使用start方法而不是run,是因为只有调用start方法才能以多线程的方式调用线程

6.通过线程对象调用start,把线程对象加入到就绪队列

更多推荐

频频刷屏朋友圈,白酒如何越来越年轻化?来聊聊白酒企业数字化

最近,某白酒品牌频频吸引大众眼球,白酒与咖啡、巧克力等联名衍生品一经推出便掀起热潮。某商品由于太过火爆,甚至一度售罄下架。不得不说,我国拥有超大规模内需市场,消费潜力巨大。当前,创新消费场景加上数字化融合转型,成为酒企品牌开疆扩土、逆势增长的重要途径。如今越来越多的酒企开始拥抱数字化,建立涵盖白酒品系开发、酒体设计、基

如何用CRM软件系统管理企业客户

客户对企业的重要程度不言而喻。可以说,客户是企业收益的来源和可持续发展的基础,客户的转化率和保留率也与企业的发展息息相关。企业想要成功转化客户,需要经历客户跟踪、挖掘、维护等一系列过程。下面我们来说说,CRM客户管理系统如何管理企业客户?1、CRM系统能从不同渠道获取客户CRM系统可以实现客户信息获取和访问、高效转化和

Js中一些数组常用API总结

前端面试题库(面试必备)推荐:★★★★★地址:前端面试题库【国庆头像】-国庆爱国程序员头像!总有一款适合你!前言Js中数组是一个重要的数据结构,它相比于字符串有更多的方法,在一些算法题中我们经常需要将字符串转化为数组,使用数组里面的API进行操作。本篇文章总结了一些数组中常用的API,我们把它们分成两类,一类是会改变原

数据信息会有哪些风险,云数据库如何保护?

数据信息安风险是多种多样的,那么,云数据库如何规避并保护数据信息安全?今天安策带大家具体来了解数据信息会有哪些风险,云数据库将如何保护:数据泄露:不管是内部人员疏忽,还是恶意攻击、系统漏洞等等原因,数据泄露会导致敏感信息的暴露,损害其品牌的声誉和利益。数据损坏:损坏原因主要由自然灾害、人为或恶意攻击构成,从而导致无法预

容器核心技术之Namespace与Cgroup

容器是一种流行的虚拟化技术,它允许我们在同一台计算机上与其他进程在独立环境中运行进程。那么容器是如何做到这一点的呢?为此,容器是从Linux内核的一些新功能构建的,其中两个主要功能是“namespace”和“cgroup”。1.Namespace1.1Namespace简介Namespace(命名空间)技术是一种内核级

Nvme Spec 第一章节学习

@NvmeExpressBaseSpecification第一章简介1.1概述NVMExpressTM(NVMeTM)接口允许主机软件与非易失性存储器子系统通信。此接口针对企业和客户端固态驱动器进行了优化,通常作为寄存器级接口连接到PCIExpress接口。注:在开发过程中,本规范被称为企业NVMHCI。然而,在完成之

YOLOv8『小目标』检测指南

前言目前博主课题组在进行物体部件的异常检测项目,项目中需要先使用YOLOv8进行目标检测,然后进行图像切割,最后采用WinCLIP模型进行部件异常检测但是在实际操作过程中出现问题,YOLOv8模型目标检测在大目标精确度不错,但是在小目标检测中效果极差我们之前的解决方案是扩大异常部件的目标检测范围,易于检测。但是缺点是会

stable diffusion在建筑行业应用

AI建筑研究室-帆哥投稿视频-AI建筑研究室-帆哥视频分享-哔哩哔哩视频点击观看AI建筑研究室-帆哥的全部投稿视频,在这里可以查看AI建筑研究室-帆哥最新发布、最多播放和最多收藏的视频。https://space.bilibili.com/2161614/videoHD▎ChatGPT接入自研AI工具集,为设计生产赋能

wkeOnDownload2与mbOnDownloadInBlinkThread

背景:最近开始实习(打工)生涯。需求:使用miniblink,显示网页,点击下载链接,可以实现下载。寻求大佬帮助,得到了wke.h版本的下载相关的代码。这里进行一些简单的分析:实际语句:wkeOnDownload2(webView,onDownloadCallback,nullptr);通过调用该函数实现:点击链接,实

SpringMVC之自定义注解

目录前言一、自定义注解1.Java注解简介2.注解的用处3.为什么要用注解4.自定义注解的应用场景5.注解的分类6.如何定义并使用自定义注解7.自定义注解三种使用案例案例一:案例二:案例三:二、Aop自定义注解的应用1.自定义注解类2.切面类3.Controller层前言随着Web开发的发展,越来越多的企业开始使用Sp

基于springboot+vue的便利店信息管理系统

博主主页:猫头鹰源码博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万+、专注Java技术领域和毕业设计项目实战主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询文末联系获取项目介绍:本系统适合选题:便利店、便利店管理、商店管理等。系统采用springb

热文推荐