返回顶部
首页 > 资讯 > 后端开发 > JAVA >【Java系列】详解多线程(一)
  • 642
分享到

【Java系列】详解多线程(一)

java开发语言java-ee 2023-12-23 16:12:45 642人浏览 独家记忆
摘要

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得,欢迎大家在评

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【Java系列专栏】【JaveEE学习专栏
本专栏旨在分享学习Java的一点学习心得,欢迎大家在评论区交流讨论💌

一、背景引入

在引入多线程之前,我们先来看一下进程是为了干什么的,一句话总结就是:满足"并发编程"这样的需求。

早些时候,CPU都是单核心的CPU,但是随着技术工艺变得越来越强,单核心CPU的性能的确是越来越强的,但是单核心CPU技术工艺研发到一定程度后就会遇到瓶颈,从而导致单核心CPU的研发变得非常缓慢。于是就就逐渐向多核心CPU的方向进行发展研究。

好了,既然CPU逐渐变成了多核心,那么应用程序也应该做出相应的调整来把多核心的CPU给利用起来(意思就是仅仅由硬件上的支撑是不够的,我们还要由软件上的配合),以免造成一核有难,多核围观的场景

另外,早期的系统一般是单任务系统,即在同一时刻只能使用一个程序,而无法在同一时刻内使用多个程序,完成多个任务。而要完成多个任务的话,进程就显得特别关键。

二、线程的引入

多进程能够很好的实现并发编程的效果,但还由一个缺点就是进程太重,即消耗资源更多,速度更慢。如果进程的创建和销毁比较少的话那还勉强可以,但是如果进程的创建和销毁非常频繁的话,此时就会产生非常多的开销。开销大主要体现在需要给进程分配资源,而给进程分配资源的这一过程也是需要很多时间成本的。

于是就有人提出这样一个解决方案:即在创建进程的过程中,只分配简单的PCB(进程控制块),而不去分配后续需要的内存硬盘资源,即把分配资源的时间省去,这样既可以完成多并发编程的任务又能够提升进程创建销毁的速度。

这样一种只分配简单的PCB而不去分配后续需要的内存硬盘资源的这样一种方式称为轻量级进程,也叫做线程(thread)。所以简单来说线程就是只分配PCB,但不分配后续需要的内存硬盘资源

但是线程总归是要完成任务的,如果不去分配后续需要的内存硬盘资源显然是不可以的,于是就有人想出来这样的一个办法:在创建进程的时候,先把后续需要的内存资源分配好;后续创建线程的时候让线程在进程内部直接复用先前进程分配创建好的内存资源(线程和进程直接的关系:进程包含线程)

另外,一个进程至少要包含一个线程,最初进程创建出来的时候,我们可以将这个进程视为一个只包含一个线程的进程(注意此时创建进程的过程是需要分配资源的,同时第一个线程的创建开销是可能是比较大的),我们后续再次创建线程的时候就不需要分配资源了,也就省去了分配资源的过程,因为资源已经是有了的。

小总结

好了,我们已经知道多进程已经可以完成并发编程的任务了,但是由于进程本身有些重,重就体现在进程的创建和销毁所需要的内存硬盘资源开销有些大。

所以就引入了线程(也称为轻量级进程)来更高的解决上述的问题。进程中的多个线程公共复用了进程中的各种内存硬盘等资源,同时这些进程可以各自独立的在CPU中进行调度。所以这样的话线程既可以完成并发编程的效果,又可以以轻量级的方式来完成各种任务。

另外,这里补充一个点,进程和线程是两个不同的概念,在Linux中复用了PCB这个结构体来描述线程,而在Windows中,描述进程和线程是不同的结构体。所以在Windows中,为了更好的描述进程,有时一个PCB对应一个线程,多个PCB对应一个进程(即可能是多一个PCB来描述一个进程,一个PCB来描述一个线程)。

CPU的内存指针和文件描述符表文件描述符表这两个字段内容在同一个进程是一样的,但是上下文信息、状态、优先级、记账信息......等支持调度的属性,这些PCB就不一样了(意思就是每个线程独立去CPU上进行调度,每个线程的上下文、状态、优先级、记账信息等支持调度的属性都有自已独立的一份)。

线程的引入的确能够提高任务执行的速度,同时随着线程数量的增多任务执行完成的速度当然也会增快,但是线程的数量不能是无限制提高的(CPU的核心数的数量是有限的。),同时线程数量也不是越多越好,因为线程调度的开销有时会拖慢整个程序的效率。

两句话总结:

1.进程是操作系统中进行资源分配的基本单位。
2.线程是操作系统中进程调度执行的基本单位。

三、进程和线程的关系(面试题

进程包含线程,都是实现并发编程的一种方式,但是由于多进程的创建和销毁的效率并没有那么高,且线程比进程更加轻量。所以就引入了多线程的概念。

进程是系统分派资源的基本单位;线程是是系统调度的基本单位,创建进程的时候已经把分配资源(这里的资源主要指的是虚拟地址空间和符表)的工作做了,后续创建进程的时候直接复用之前的资源即可。

每个进程都有自己独立的地址空间,彼此直接不会相会影响到,从而保证了每个进程的独立性,保证了数据稳定性。
需要注意的是,如果多个组线程程共用了一份地址空间的话,一旦某个线程抛出异常的话,就可能会导致一整个进程结束(所以多个线程之间是很容易相互影响的。 )。

四、第一个多线程程序

线程本身是操作系统的概念,而操作系统又提供了api来供我们使用线程,来完成多线程编程(在linux中称为pthread库,通过这个库我们就可以完成多线程编程)。

而在Java中,把操作系统中的API进程分装,即提供了Thread类来帮助哦我们来完成多线程编程。

Java标准库中的Thread类来自于java.lang这个包,而Java.lang这个包不需要我们手动的import

好了,光说不练是不行的,接下来我们就来看一下我们的第一个线程程序,请看下图:

package thread;class MyThread extends Thread {    @Override    public void run() {        System.out.println("Hello,world!");    }}public class Demo01 {    public static void main(String[] args) {        MyThread myThread = new MyThread();        myThread.start();    }}

现在我们来解释上述的线程程序,上述代码的MyThread类中的run()方法是重写的Thread父类中的run()方法,这个run()方法相当于线程程序的入口,线程程序跑起来之后具体要干什么事情,都是通过这个run()方法来进行描述的。

myThread.start()这个操作就是在创建一个线程(即在底层调用操作系统提供的创建线程的API,同时在操作系统内核中创建出其对应的PCB结构,并将其加入到链表中)。此时这个新创建出来的线程就会参与到cpu的调度中,接下来线程要执行的任务,就是run()方法中的内容。

接下来我如果注释掉myThread.start();,即直接执行MyThread类中的run()方法,请看下图:
在这里插入图片描述
我们来解释上述程序,我们前面已经知道,start方法会去调用操作系统提供的创建线程的API,同时在操作系统内核中创建出其所对应的PCB,此时这个新创建出来的线程就会参与cpu调度
而我们直接运行run方法的话,此时并没有调用操作系统提供的创建线程的API,也就没有创建出新的进程。
当整个程序开始运行的时候,此时会先创建出来一个java进程,这个java进程中至少包含一个进程,称为主进程,这个主进程是负责执行main()方法的线程。每一个线程都能够被独立的进行调用和执行。

每个线程都能够被独立的进行调用执行

每个线程都能够被独立的进行调用执行,现在我们来写一个程序来体现这句话。请看:

在这里插入图片描述
运行结果如下(由于程序是一个死循环,所以这里只是截取了部分的程序运行结果),如下图:
在这里插入图片描述
我们可以看到程序一会执行Hello,Linux!一会执行Hello,world!
解释:start()是新线程执行的入口,而主线程和新线程是并发执行的一个关系。先新创建出来的线程创建出来之后会执行run()方法中的代码,而main()方法则是继续往后执行。所以最终呈现出来的程序运行效果就是一会执行Hello,Linux!,一会执行Hello,world!

现在我们在来看一段程序,请看下图:
在这里插入图片描述
我们可以看到上述代码把myThread.start()注释掉了,相当于我们并没有创建线程,那么此时的话只有整个程序只有主线程这一个线程了。
分析到这里我们已经知道整个程序只有线程(也就是主线程),那么执行的run()方法就是在主线程中去执行的,因为整个程序就只有一个线程(即主线程)。

总结一下:

  • 每个线程都是一个独立的执行流。
  • 每个线程都可以执行一段代码。
  • 每个线程之间是并发的关系。

好了,本文到这里就结束了,就到这里吧,再见啦友友们!!!在这里插入图片描述

来源地址:https://blog.csdn.net/m0_74352571/article/details/134854786

--结束END--

本文标题: 【Java系列】详解多线程(一)

本文链接: https://lsjlt.com/news/551706.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 【Java系列】详解多线程(一)
    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得,欢迎大家在评...
    99+
    2023-12-23
    java 开发语言 java-ee
  • 【Java系列】详解多线程(三)—— 线程安全(下篇)
    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得,欢迎大家在评...
    99+
    2023-12-22
    java 安全 多线程 java-ee
  • 【Java系列】深入解析Java多线程
    序言 你只管努力,其他交给时间,时间会证明一切。 文章标记颜色说明: 黄色:重要标题红色:用来标记结论绿色:用来标记一级重要蓝色:用来标记二级重要 希望这篇文章能让你不仅有一定的收获,而且可以愉快的学习,如果有什么建议...
    99+
    2023-08-31
    java 开发语言 jvm
  • Java多线程案例之阻塞队列详解
    目录一.阻塞队列介绍1.1阻塞队列特性1.2阻塞队列的优点二.生产者消费者模型2.1阻塞队列对生产者的优化三.标准库中的阻塞队列3.1Java提供阻塞队列实现的标准类3.2Block...
    99+
    2022-11-13
    Java多线程阻塞队列 Java 阻塞队列 Java多线程
  • 【Java系列】详解多线程(二)——Thread类及常见方法(上篇)
    个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【Java系列专栏】【JaveEE学习专栏】 本专栏旨在分享学习Java的一点学习心得,欢迎大家在评...
    99+
    2023-12-23
    java 开发语言 java-ee
  • C#多线程系列之async和await用法详解
    目录async和awaitasyncawait从以往知识推导创建异步任务创建异步任务并返回Task异步改同步说说 await Task说说 async Task<TR...
    99+
    2024-04-02
  • JAVA多线程详解(超详细)
    目录 一、线程简介1、进程、线程2、并发、并行、串行3、进程的三态 二、线程实现1、继承Thread类2、实现Runnable接口3、实现Callable接口(不常用) 三、线程常用方法1、线程的状态2、线程常用方法 四...
    99+
    2023-08-19
    java jvm 开发语言
  • Java多线程之线程状态详解
    目录 线程状态停止线程线程休眠模拟网络延迟(放大问题的发生性)模拟计时线程礼让插队(线程强制执行)线程状态观测线程优先级守护线程总结 线程状态 五个状态:新生、就...
    99+
    2024-04-02
  • C#多线程系列之线程池
    目录线程池ThreadPool 常用属性和方法线程池说明和示例线程池线程数线程池线程数说明不支持的线程池异步委托任务取消功能计时器线程池 线程池全称为托管线程池,线程池受 .NET ...
    99+
    2024-04-02
  • java多线程:基础详解
    目录Java内存模型主内存和工作内存的交互命令内存模型的原子性内存模型的可见性内存模型的有序性指令重排优化的底层原理valatile原理volatile与加锁的区别先行发生原则线程的...
    99+
    2024-04-02
  • Java多线程(二)——synchronized 详解
    目录 1 volatile 关键字 1.1保证变量可见性 1.2 不能保证数据的原子性举例 1.3 禁止JVM指令重排序 2 synchronized 关键字 2.1 概念及演进 2.2 对象锁和类锁 2.3 synchronized 的...
    99+
    2023-09-02
    java jvm 开发语言
  • C#多线程系列之任务基础(一)
    目录多线程编程多线程编程模式探究优点任务操作两种创建任务的方式Task.Run() 创建任务取消任务父子任务任务返回结果以及异步获取返回结果捕获任务异常全局捕获任务异常多线程编程 多...
    99+
    2024-04-02
  • Java多线程之Interrupt中断线程详解
    目录一、测试代码二、测试三、执行过程描述四、输出日志五、结论六、主要方法释义七、DEMO八、拓展程序九、实战一、测试代码 https://gitee.com/zture/sprin...
    99+
    2024-04-02
  • 【Java 线程系列 】线程池原理解析--看这一篇就够了
    作者:半身风雪 上篇:阻塞队列原理解析 线程池原理解析 一、为什么要用线程池 二、ThreadPoolExecutor 的类关系 三、线程池的创建各个参数含义 ...
    99+
    2023-08-31
    java 开发语言 android
  • C#多线程系列之线程通知
    AutoRestEvent 类用于从一个线程向另一个线程发送通知。 微软文档是这样介绍的:表示线程同步事件在一个等待线程释放后收到信号时自动重置。 其构造函数只有一个: 构造函数里面...
    99+
    2024-04-02
  • C#多线程系列之线程等待
    目录前言volatile 关键字三种常用等待再说自旋和阻塞SpinWait 结构属性和方法自旋示例新的实现SpinLock 结构属性和方法示例等待性能对比前言 volatile 关键...
    99+
    2024-04-02
  • Java多线程(单例模式,阻塞队列,定时器,线程池)详解
    目录1. 单例模式(singleton pattern)1.1 懒汉模式1.2 饿汉模式2 阻塞队列(blocking queue)2.1 阻塞队列2.2 生产者消费者模型2.3 标...
    99+
    2024-04-02
  • Java多线程编程详细解释
    目录一、多线程的优缺点多线程的优点:多线程的代价:二、创建java多线程1、创建Thread的子类2、实现Runnable接口三、线程安全四、java同步块五、java线程通信六、j...
    99+
    2024-04-02
  • 详解Java多线程与并发
    目录一、进程与线程二、并发与并行1、线程安全问题2、共享内存不可见性问题三、创建线程1、继承Thread类2、实现Runable接口3、实现Callable接口四、Thread类详解...
    99+
    2024-04-02
  • Java多线程之死锁详解
    目录1、死锁2、死锁经典问题——哲学家就餐问题 总结1、死锁 出现场景:当线程A拥有了A对象的锁,想要去获取B对象的锁;线程B拥有了B对象的锁,想要拥有A对象的锁,两个线程...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作