【JAVA】线程和进程

news2024/11/15 11:26:40

在这里插入图片描述

🏆今日学习目标:线程和进程
😃创作者:颜颜yan_
✨个人主页:颜颜yan_的个人主页
⏰本期期数:第三期
🎉专栏系列:JAVA


线程和进程

  • 前言
  • 一、进程与线程
    • 1.进程
    • 2.线程
  • 二、线程的创建
    • 2.1 继承Thread类创建多线程
    • 2.2 实现Runnable接口创建多线程
    • 2.3 实现Callable接口创建多线程
    • 总结


前言

多线程是提升程序性能非常重要的一种方式,也是Java 编程中的一项重要技术。在程序设计中,多线程就是指一个应用程序中有多条并发执行的线索,每条线索都被称作—个线程,它们会交替执行,彼此可以通信。


一、进程与线程

1.进程

进程(process) 是计算机中程序的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。

虽然进程在程序执行时产生,但进程并不是程序。程序是“死”的,进程是“活”的。程序是指编译好的二进制文件,它存放在磁盘上,不占用系统资源,是具体的;而进程存在于内存中,占用系统资源,是抽象的。当一次程序执行结束时,进程随之消失,进程所用的资源被系统回收。

对计算机用户而言,计算机似乎能够同时执行多个进程,如听音乐、玩游戏、语音聊天等等,都能在同一台计算机上同时进行。但实际上,一个单核的 CPU 同一时刻只能处理一个进程,用户之所以认为同时会有多个进程在运行,是因为计算机系统采用了多道程序设计技术。

所谓多道程序设计,是指计算机允许多个相互独立的程序同时进人内存,在内存的管理控制之下,相互之间穿插运行。多道程序设计必须有硬件基础作为保障。

采用多道程序设计的系统,会将 CPU 的周期划分为长度相同的时间片,在每个 CPU时间片内只处理一个进程,也就是说,在多个时间片内,系统会让多个进程分时使用 CPU。假如现在内存中只有3个进程A、B、C,那么CPU 时间片的分配情况大致如下图。
在这里插入图片描述

虽然在同一个时问片中,CPU 只能处理一个进程,但 CPU 划分的时间片是非常微小的,且 CPU 运行速度极快(1 秘可执行约10亿条指令),因此,在宏观上并发执行多个程序、处理多个进程。

进程对 CPU 的使用权是由操作系统内核分配的,操作系统内核必须知道内存中有多少个进程,并且知道此时正在使用 CPU 的进程,这就要求内核必须能够区分进程,并可获取进程的相关属性。

2.线程

通过上述节的介绍可以知道,每个运行的程序都是一个进程,在一个进程中还可以有多个执行单元同时运行,这些执行单元可以看作程序执行的线程(thread)。每一个进程中都至少存在一个线程。例如,当一个Java 程序启动时,就会产生一个进程,该进程默认创建一个线程,这个线程会运行main()方法中的代码。

在程序中,代码都是按照调用顺序依次往下执行的,没有出现两段程序代码交替运行的效果,这样的程序称作单线程程序。如果希望程序中实现多段程序代码交替运行的效果,则需要创建多个线程,即多线程程序。所谓多线程是指一个进程在执行过程中可以产生多个线程,这些线程在运行时是相互独立的,它们可以并发执行。多线程程序的执行过程如图 。

图中的多条线程看起来是同时执行的;其实不然,图中多线程程序的执行过程它们和进程一样,也是由 CPU 轮流执行的,只不过 CPU 运行速度很快,因此给人同时执行的感觉。
在这里插入图片描述

二、线程的创建

Java 提供厂3种多线程的创建方式:

(1)继承 java.lang 包中的 Thread 类,重写 Thread 类的run()方法,在run()方法中实
现多线程代码。
(2)实现 java.lang.Runnable 接口,在run()方法中实现多线程代码。
(3)实现 java.util.concurrent.Callable 接口,重写 callO方法,并使用 Future 接口获取call()方法返回的结果。

2.1 继承Thread类创建多线程

Main类

public class Main {
    public static void main(String[] args) {
        MyThread1 myThread = new MyThread1();      //创建MyThread1类的实例对象
        myThread.run();                            //调用Mythread1类的run方法
        while (true){                             //死循环,输出信息
            System.out.println("main()方法在运行");
        }

    }
}

MyThread1类

public class MyThread1 {
    public void run(){
        while (true){                                        //死循环,输出信息
            System.out.println("MyThread类的run方法在运行");
        }
    }
}

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

从图中可以看出,程序一直打印“My Thread 类的run()方法在运行”,这是因为该程序是一个单线程程序。在第一幅图的代码调用 MyThread1 类的run()方法时,执行第 MyThread1 类代码定义的死循环,因此,MyThread 类的 printin 语句将一直执行,而main()方法中的 printin 语句无法得到执行。

如果希望两个while 循环中的println 语句能够并发执行,就需要实现多线程。为此Java 提供了线程类 Thread。通过继承 Thread 类,并重写 Thread 类中的run()方法,便可实现生线程。在Thread 类中提供了 start()方法用于启动新线程。新线程启动后,Java虚拟机会自动调用 run()方法;如果子类重写了run()方法,便会执行子类中的run()方法。

2.2 实现Runnable接口创建多线程

上面通过继承 Thread 类实现了多线程,但是这种方式有一定的局限性。因为Java 只支持单继承,一个类一旦继承了某个父类,就无法再继承 Thread 类。例如,Studert类继承了Person 类,那么Student 类就无法再通过继承 Thread 类创建线程。

为了克服这种弊端,Thread 类提供了另一个构造方法——Thread (Runnable target),其中参数类型 Runnable 是一个接口,它具有一个run()方法。通过Thread(Runnabiletarget)构造方法创建线程对象时,只需为该方法传递一个实现了 Runnable 接口的对象,这样,创建的线程将实现 Runnable 接口中的run()方法作为运行代码,而不需要调用 Thread类中的run()方法。

下面通过案例演示如何通过实现 Runnable 接口的方式创建多线程,如图所示:

Main类

public class Main {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();  //创建MyThread2类的实例对象
        Thread thread = new Thread();    // 创建线程对象
        thread.start();             //开启线程,执行线程中的run()方法
        while (true){
            System.out.println("main()方法在运行");
        }

    }
}

MyThread2类

public class MyThread2 implements Runnable{
    public void run() {              //线程的代码段,当调用start()方法时,线程从此开始执行
        while (true){
            System.out.println("MyThread类的run()方法在运行");
        }
    }

}


在代码中,代码定义的 MyThreado2 类实现了 Runnable 接口,并在中代码中重写了 Runnable 接口中的run()方法。在Main代码通过调用Thread类的构造方法将NyThread2类的实例对象作为参数传入。代码中调用 strar()方法开启新线程执行 MyThread2 关中的代码。而主线程继续执行 main()方法中的代码。

运行结果如图:
在这里插入图片描述
从图中可以看出来,main()和MyThread2类中的run()方法都被执行了,说明实现了多线程

2.3 实现Callable接口创建多线程

通过 Thread 类和 Runnable 接口实现多线程时,需要重写run()方法,但是由于run()f方法没有返回值,无法从新线程中获取返回结果。为了解决这个问题,Java 提供了Callable接口来满足这种既能创建新线程又有返回值的需求。

通过实现 Callable 接口的方式创建并启动线程的主要步骤如下:
(1)创建 Callable 接口的实现类,同时重写 Callable 接口的call()方法。
(2)创建 Callable 接口的实现类对象。
(3)通过线程结果处理类 FutureTask 的有参构造方法封装 Callable 接口的实现类
对象。
(4)调用参数为 FutureTask 类对象的有参构造方法 Thread() 创建 Tbread 线程实例。
(5)调用线程实例的 start()方法启动线程。
下面通过一个案列演示如何通过买现 Callable 接口的方式来实现多线程,如下面文件所示。

Main

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Mythread3 myThread = new Mythread3();  //创建Callable接口类的实例对象
        //使用FuntureTask封装Mythread3类
        FutureTask ft1 = new FutureTask(myThread);
        //使用Thread(Runnable target,String name)构造方法创建线程对象
        Thread thread1 = new Thread(ft1,"thread");
        //调用线程对象的start()方法启动线程
        thread1.start();
        //通过FuntureTaskdioxin的方法管理返回值
        System.out.println(Thread.currentThread().getName()+"的返回结果:"+ft1.get());
        int a=0;
        while (a++<5){
            System.out.println("main()方法在运行");
        }

    }
}

MyThread3类

import java.util.concurrent.*;
public class Mythread3 implements Callable {
    //重写Callable接口中的call()方法
    public Object call() throws Exception{
        int i=0;
        while (i++<5){
            System.out.println(Thread.currentThread().getName()+"的call()方法在运行");
        }
        return i;
    }
}

在上述文件中,在MyThread3类代码定义了一个实现 Callable 接口的实现类,并在 Calalble接口中重写了call()方法。在Main中,代码创建了 Callable接口的实例,并调用有参的Thread()构造方法创建了线程对象thread1。在代码中调用线程对象 thread1的 start()方法启动线程。

运行结果如图所示:
在这里插入图片描述
从图可以看出,所示的案例通过实现 Callable 接口的方式实现了多线程开且有返回结果。

Callable 接口方式实现的多线程是通过 Future Task 类来封装和管理返回结果的,Future Task 类的直接父接口是RunnableFuture,从名称上可以看出 RunnableFuture 是Runnable 和Future的结合体。

总结

以上就是今天的学习内容啦~
如果有兴趣的话可以订阅专栏,持续更新呢~
咱们下期再见~
在这里插入图片描述

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

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

相关文章

Pytest自动化框架~权威教程03-原有TestSuite的执行方法

前言TestSuite一直是unittest的灵活与精髓之处, 在繁多的测试用例中, 可以任意挑选和组合各种用例集, 比如smoke用例集, level1用例集, webtest用例集, bug回归用例集等等, 当然这些TestSuite需要我们提前定义好, 并把用例加载进去.Pytest采取的是完全不同的用例组织和运行方式…

有些笑话,外行人根本看不懂,只有程序员看了会狂笑不止

我一直都觉得我们写代码的程序员与众不同&#xff0c;就连笑话都跟别人不一样。 如果让外行人来看我们一些我们觉得好笑的东西&#xff0c;他们根本不知道笑点在哪里。 不信你来瞧瞧&#xff0c;但凡有看不懂的地方&#xff0c;说明你的道行还不够深。 1.大多数人开始学编程时…

论文解读14——XGBoost:A Scalable Tree Boosting System

目录1、文章贡献2、算法推导3、寻找分裂点算法3.1 精确贪心算法3.2 近似算法4、稀疏感知算法5、特征维度的并行化6、XGBoost VS GBDT7、XGBoost局限半年前看了这篇XGBoost的原文&#xff0c;网上解读很多&#xff0c;于是迟迟没有将其中的精髓记录下来&#xff0c;准备重点记一…

从工厂打螺丝到月薪18k测试工程师,我该满足吗?

以前我比较喜欢小米那句“永远相信美好的事情即将发生”&#xff0c;后来发现如果不努力不可能有美好的事情发生&#xff01;01高中毕业进厂5年&#xff0c;创业经商多次战败&#xff0c;为了生计辗转奔波高中毕业后我就进了工厂&#xff0c;第一份工作是做模具加工。从500元一…

1.基于Label studio的训练数据标注指南:信息抽取(实体关系抽取)、文本分类等

文本抽取任务Label Studio使用指南 1.基于Label studio的训练数据标注指南&#xff1a;信息抽取&#xff08;实体关系抽取&#xff09;、文本分类等 2.基于Label studio的训练数据标注指南&#xff1a;&#xff08;智能文档&#xff09;文档抽取任务、PDF、表格、图片抽取标注等…

网络资源面经2

文章目录Kafka 原理&#xff0c;数据怎么平分到消费者生产者分区消费者分区Flume HDFS Sink 小文件处理Flink 与 Spark Streaming 的差异&#xff0c;具体效果Spark 背压机制具体实现原理Yarn 调度策略Spark Streaming消费方式及区别Zookeeper 怎么避免脑裂&#xff0c;什么是脑…

用Python自己写一个分词器,python实现分词功能,隐马尔科夫模型预测问题之维特比算法(Viterbi Algorithm)的Python实现

☕️ 本文系列文章汇总&#xff1a; &#xff08;1&#xff09;HMM开篇&#xff1a;基本概念和几个要素 &#xff08;2&#xff09;HMM计算问题&#xff1a;前后向算法 代码实现 &#xff08;3&#xff09;HMM学习问题&#xff1a;Baum-Welch算法 代码实现&#xff08…

【数据结构】关于二叉树你所应该知道的数学秘密

目录 1.什么是二叉树&#xff08;可以跳过 目录跳转&#xff09; 2.特殊的二叉树&#xff08;满二叉树/完全二叉树&#xff09; 2.1 基础知识 2.2 满二叉树 2.3 完全二叉树 3.二叉树的数学奥秘&#xff08;主体&#xff09; 3.1 高度与节点个数 3.2* 度 4.运用二叉树的…

算法拾遗二十五之暴力递归到动态规划五

算法拾遗二十七之暴力递归到动态规划七题目一【数组累加和最小的】题目二什么暴力递归可以继续优化暴力递归和动态规划的关系面试题和动态规划的关系如何找到某个问题的动态规划方式面试中设计暴力递归的原则知道了暴力递归的原则 然后设计常见的四种尝试模型如何分析有没有重复…

力扣-丢失信息的雇员

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1965. 丢失信息的雇员二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他…

SpringBoot高级-Condition相关操作

01-SpringBoot高级-今日内容 SpringBoot自定配置SpringBoot事件监听SpringBoot流程分析SpringBoot监控SpringBoot部署 02-SpringBoot自动配置-Condition-1 Condition是Spring4.0后引入的条件化配置接口&#xff0c;通过实现Condition接口可以完成有条件的加载相应的Bean Co…

移动架构43_什么是Jetpack

Android移动架构汇总​​​​​​​ 文章目录一 Android 开发框架演变1 MVC2 MVP3 MVVM二 什么是JetPack三 如何构建支持Jetpack项目一 Android 开发框架演变 1 MVC Model-View-Controller&#xff0c;模型-视图-控制器&#xff0c;Model负责数据管理&#xff0c;View负责UI显…

创建Vite+Vue3+TS基础项目

前言&#xff1a; 本篇内容不涉及插件的安装以及配置&#xff0c;具体安装及配置篇可以看下面目录&#xff0c;本篇只涉及创建ViteVue3TS基础项目相关内容。不讲废话&#xff0c;简单直接直接开撸。 目录 npm create vite vue3练习2 -- --template vue-ts npm i vue-rout…

线性表 顺序表数组

初识线性表 文章目录初识线性表线性表的类型定义基本操作&#xff08;一&#xff09;init&#xff0c;destory&#xff0c;clear基本操作&#xff08;二&#xff09; 判空 &#xff0c;求长基本操作&#xff08;三&#xff09;取值&#xff0c;取位置基本操作&#xff08;四&am…

图解LeetCode——剑指 Offer 12. 矩阵中的路径

一、题目 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平相…

Solon2 的应用生命周期

Solon 框架的应用生命周期包括&#xff1a;一个初始化函数时机点 六个事件时机点 两个插件生命时机点 两个容器生命时机点&#xff08;v2.2.0 版本的状态&#xff09;&#xff1a; 提醒&#xff1a; 启动过程完成后&#xff0c;项目才能正常运行&#xff08;启动过程中&…

基于麻雀算法改进的BP神经网络客流量预测,SSA-BP

目录 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的基本结构 BP神经网络的神经元 BP神经网络的激活函数&#xff0c; BP神经网络的传递函数 麻雀算法原理 麻雀算法主要参数 麻雀算法流程图 麻雀算法优化测试函数代码 基于麻雀算法改进的BP神经网络坑基监测 数据 matlab…

Windows 11 安装 Docker Desktop

Windows 环境安装 WSL2 WSL 简介 WSL 全称是 Windows Subsystem for Linux &#xff0c;适用于 Linux 的 Windows 子系统&#xff0c;可让开发人员按原样运行 GNU/Linux 环境&#xff0c;包括大多数命令行工具、实用工具和应用程序&#xff0c;且不会产生传统虚拟机或双启动设…

低线城市外卖市场逐渐下沉,创业者如何有效开展本地外卖平台

近年来&#xff0c;我国网上外卖营业额不断上升&#xff0c;使我国餐饮业的比重越来越高。 随着外卖市场的下沉&#xff0c;低线城市的用户开始使用外卖平台 由于我国在线外卖行业逐渐成熟&#xff0c;一、二线主流市场逐渐饱和&#xff0c;外卖行业逐渐开始向低线城市发展&…